Skip to content
isdnetworks
Go back

주소가 코드에 통째로 박혀 있었다

시험 서버를 새로 만들었는데 이미지가 안 보이고 링크를 누르면 운영으로 갔다.

Table of contents

Open Table of contents

주소가 박혀 있었다

코드는 이랬다.

echo '<img src="http://shop.example.com/upload/' . $file . '">';
redirect('http://shop.example.com/order/complete');

시험 서버에서도 운영 주소를 부른다. 이미지는 운영에서 가져오고 주문을 끝내면 운영으로 넘어간다. 링크만 넘어가는 것이 아니라 자료를 바꾸는 요청도 운영으로 가서 시험하다 운영 자료를 건드릴 뻔했다.

몇 군데인지 셌다.

$ grep -rn "http://shop.example.com" --include=*.php application/ | wc -l
142

142곳이었고 뷰 파일이 대부분이며 컨트롤러에도 있었다.

$ grep -rln "http://shop.example.com" --include=*.php application/ | wc -l
38

파일로는 38개다.

세어 놓아야 고친 뒤에 남은 것이 있는지 알 수 있다. 세지 않고 고치면 다 고쳤다고 생각하게 된다. 이 숫자가 나중에 확인의 기준이 됐다.

설정에서 가져오게 바꿨다

CodeIgniter 에는 이미 그런 자리가 있었다.

// config.php
$config['base_url'] = 'http://shop.example.com/';
echo '<img src="' . base_url('upload/' . $file) . '">';
redirect('order/complete');

redirect 는 원래 상대 경로를 받는데 절대 주소를 넣고 있었던 것이다.

환경마다 다르게도 정했다.

// config.php
$host = $_SERVER['HTTP_HOST'] ?? 'shop.example.com';
$config['base_url'] = 'http://' . $host . '/';

붙은 주소를 그대로 쓰게 하면 서버를 늘려도 설정을 안 고친다. 다만 이렇게 하면 요청 헤더를 믿는 것이 되고 HTTP_HOST 를 조작해 다른 주소로 링크가 만들어질 수 있다.

$allowed = ['shop.example.com', 'test.example.com', 'localhost'];
$host = in_array($_SERVER['HTTP_HOST'] ?? '', $allowed, true)
      ? $_SERVER['HTTP_HOST'] : 'shop.example.com';

$allowed 에 있는 것만 쓴다.

헤더를 그대로 믿는 것과 목록으로 거르는 것의 차이는 한 줄이었다. 그 한 줄이 없으면 링크가 남의 주소로 만들어질 수 있다. 편한 쪽과 안전한 쪽이 갈리는 자리였다.

이미지 주소는 나중에 다른 서버에 둘 수 있어서 따로 뺐다.

$config['asset_url'] = 'http://shop.example.com/upload/';

지금은 같은 자리를 가리키지만 asset_url 로 나눠 두니 이미지 서버를 옮길 때 한 줄만 고치면 된다.

저장된 자료에도 있었다

코드만 고쳐서 될 일이 아니었다.

SELECT COUNT(*) FROM board WHERE content LIKE '%http://shop.example.com%';
842

게시글 본문에 주소가 들어 있었다. 편집기가 이미지를 넣을 때 절대 주소로 넣고 있었다.

이미 들어간 것은 그대로 두고 앞으로 들어가는 것을 상대 경로로 바꿨다. 옛 글을 고치면 이력이 남지 않아서 위험했기 때문이다.

$content = str_replace('http://shop.example.com/upload/',
                       $this->config->item('asset_url'), $row['content']);

읽을 때 str_replace 로 바꿔서 보여 주는 것으로 했다.

저장된 값은 손대지 않으니 되돌릴 일도 없다. 새로 저장할 때는 주소를 빼고 넣게 했다. 옛것은 변환으로 다루고 새것은 처음부터 안 넣는 두 갈래였다.

검증 — 다시 세어 본 남은 것

다 고쳤다고 생각한 뒤에 한 번 더 찾아봤다.

$ grep -rn "http://shop" --include=*.php application/
(없음)
$ grep -rn "https\?://[a-z.]*example" --include=*.php application/ | grep -v config.php

두 번째 명령으로 다른 형태도 찾았다. https 로 적힌 것과 다른 하위 도메인이 세 곳 더 있었다. 한 문자열로만 찾으면 남는다.

고치고 나서 시험 서버에서 열어 봤다.

$ curl -s http://test.example.com/product/1 | grep -o 'src="[^"]*"' | head
src="http://test.example.com/upload/a.jpg"

시험 주소가 나온다. 운영 주소가 하나라도 나오면 아직 남은 것이다.

세어 본 숫자가 0이 되는 것과 화면에서 확인하는 것은 다른 검증이었다. 앞은 소스에 없다는 것이고 뒤는 실제로 안 나온다는 것이다. 둘을 다 봐야 끝난 것이 된다.

정리


Share this post on:

Previous Post
컨트롤러가 다 하고 있었다
Next Post
화면대로 테이블을 만들었다