그누보드의 지속적인 발전을 기대하는 php전문가입니다.
이미 세계적으로 유명한 Acunetix 소프트웨어를 이용해 그누보드의 취약성 등급을 추정한바 있습니다.
[https://sir.kr/g5_tip/14784] 여길 잠간 봐주시면 저의 노력 아시게 됩니다.
이 시간에는
그누보드소스에서 공통적이면서도 무시되고 있는 중요한 허점에 대하여 논하려고 합니다.
php코드는 당연히 <?php로 시작해서 ?>로 끝내야 합니다.
그러나 php업체의 공개문서에 따르면 오직 php코드만 있는 코드파일에서는 끝 태그인 '?>'을 사용하지 않는것이 매우 중요함을 알수 있습니다.
아래에 해당 부분 발췌하였습니다.
If a file contains only PHP code, it is preferable to omit the PHP closing tagat the end of the file. This prevents accidental whitespace or new linesbeing added after the PHP closing tag, which may cause unwanted effectsbecause PHP will start output buffering when there is no intention fromthe programmer to send any output at that point in the script.
간단히 역하면, php코드만 있는 파일에서 끝 태그 ?> 다음에 공백문자나 빈 행바꾸기 등이 삽입되어 있는 경우 최종 코드 실행후 출력 값이 프로그래머가 원하는 값이 아니될수 있다는것입니다.
그럼 간단한 예로 이 부분 이해해보기로 하겠습니다.
3개 파일 준비하겠습니다. 첨부파일로 전체 코드 올렸습니다.
common.php
<?php
function checkPassword($val) {
/*
* 디비 조회하여 비번 비교 한 결과를 부울린 타입으로 리턴한다고 가정!!!
* 현재는 true로 매번 리턴!!!
*/
return true; // 또는 false
}
/*
* 주의!!!
* ?> 기호 다음에 빈 행 2개 추가 되었음!!!
*/
?>
test.php
<?php
require_once 'common.php';
$password = $_POST['password'];
$result = checkPassword($password); // 현재는 checkPassword()함수가 true만을 리턴하므로 '성공' 출력!
if($result) {
echo '성공';
} else {
echo '실패';
}
/*
* 주의!!!
* ?> 기호 다음에 탭 문자열 삽입 되었음!!!
*/
?>
index.html파일을 작성합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="jquery-3.2.1.min.js"></script>
<script>
function getData() {
$.ajax({
url: "test.php",
type: "POST",
data: {password: '123'},
success: function (result) {
console.log(result);
if(result == '성공') {
alert('비번 통과 성공!');
} else {
alert('비번 통과 실패!'); // 왜 test.php에서는 '성공'문자열을 리턴해주는데 여기에 걸릴가??????????????????????
}
}
});
}
$(document).ready(function() {
getData(); // test.php에 요청
});
</script>
</head>
<body>
</body>
</html>
이제 웹 브라우저에서 http://localhost/sample/index.html 링크 테스트합니다.
당연히 '성공' 값이 리턴되어 '비번 통과 성공!' 메시지 뜰것이라 믿는 분 계실겁니다.
그런데 실제 보면 test.php가 출력한 값은 빈 행 3개와 뒤끝에 탭이 하나 더 추가된 문자열 즉
'성공'
로, 우리가 원하는 결과값의 앞과 뒤에 빈 행과 탭이 추가되었습니다.
꼭 ajax로 요청보내서 리턴값을 확인해보세요.
예를 통해 보는것 처럼, php 끝 태그 ?> 다음에 눈에는 보이지 않는 공백, 행바꾸기, 탭 등이 있다면 최종 출력값에 이 공백, 행바꾸기 같은것들이 함께 삽입되어 리턴됩니다.
위의 예에서 '성공' 문자열이 리턴 되었지만 사실상 그 앞에 빈 행이 추가되었기 때문에 if(result == '성공') 결과값 비교가 실패하여 alert('비번 통과 실패!');가 작동하게 됩니다.
이렇게 우리는 ?> 태그 다음에 삽입된 공백이나 행바꾸기, 탭 등이 얼마나 큰 허점을 발생시키는지 알게 되었습니다.
php개발과정에 이 문제를 소홀히 하시면 도무지 알수 없는 결과에 당황해져 그 디버깅에 아까운 시간 소모하시게 됩니다.
저도 이런 문제 한번 당했는데, 호상 연동하는 파일들이 너무 많으니 어디서 문제가 발생하고 있는지 몰라서, 끝내 찾아내지 못하구, 결과값을 리턴하기 전에 ob_end_clean()함수를 써서 모면했더랬는데... 바로 이 문제였거든요, 그래서 차후로는 절대 php 끝 기호 ?> 을 망탕 쓰지 않습니다.
php는 php코드로만 작성된 파일에서 끝 기호 ?> 가 없으면 자동적으로 코드마감을 인지하여 처리함으로써 개발자들이 위의 문제에 집중하지 않도록 해줍니다.
그누보드가 바로 이 허점 소홀히 하는거 같아요.
1000개 이상이나 되는 php파일들이 모두 ?> 기호를 사용하였고, ?> 기호 다음에 빈 행이 들어간것도 많고요...
ajax기능도 사용했는데 위의 예처럼 된 부분 있으면 정말 안타까운 문제를 당하고 맙니다.
때문에 그누보드의 모든 php코드파일들 전부 이 문제 고려해서 시급히 수정할것을 정중히 제의드리는 바입니다.
/theme/basic/head.php 파일처럼 php코드와 html, 자바스크립트가 엉킨 코드파일은 이 문제 제기되지 않으니 염려마시고요, 오직 php코드만으로 작성된 코드파일들은 php 끝 기호 ?> 를 제거함이 깨끗한 코드품질을 담보하는것이라 얘기마치게 됩니다.
그리고 그누보드 아름답게 확장하시는 모든 개발자분들도 위의 규칙 고려하여 배포해주세요.
마지막까지 보아주신 여러분께 감사드립니다.
이미 세계적으로 유명한 Acunetix 소프트웨어를 이용해 그누보드의 취약성 등급을 추정한바 있습니다.
[https://sir.kr/g5_tip/14784] 여길 잠간 봐주시면 저의 노력 아시게 됩니다.
이 시간에는
그누보드소스에서 공통적이면서도 무시되고 있는 중요한 허점에 대하여 논하려고 합니다.
php코드는 당연히 <?php로 시작해서 ?>로 끝내야 합니다.
그러나 php업체의 공개문서에 따르면 오직 php코드만 있는 코드파일에서는 끝 태그인 '?>'을 사용하지 않는것이 매우 중요함을 알수 있습니다.
아래에 해당 부분 발췌하였습니다.
If a file contains only PHP code, it is preferable to omit the PHP closing tagat the end of the file. This prevents accidental whitespace or new linesbeing added after the PHP closing tag, which may cause unwanted effectsbecause PHP will start output buffering when there is no intention fromthe programmer to send any output at that point in the script.
간단히 역하면, php코드만 있는 파일에서 끝 태그 ?> 다음에 공백문자나 빈 행바꾸기 등이 삽입되어 있는 경우 최종 코드 실행후 출력 값이 프로그래머가 원하는 값이 아니될수 있다는것입니다.
그럼 간단한 예로 이 부분 이해해보기로 하겠습니다.
3개 파일 준비하겠습니다. 첨부파일로 전체 코드 올렸습니다.
common.php
<?php
function checkPassword($val) {
/*
* 디비 조회하여 비번 비교 한 결과를 부울린 타입으로 리턴한다고 가정!!!
* 현재는 true로 매번 리턴!!!
*/
return true; // 또는 false
}
/*
* 주의!!!
* ?> 기호 다음에 빈 행 2개 추가 되었음!!!
*/
?>
test.php
<?php
require_once 'common.php';
$password = $_POST['password'];
$result = checkPassword($password); // 현재는 checkPassword()함수가 true만을 리턴하므로 '성공' 출력!
if($result) {
echo '성공';
} else {
echo '실패';
}
/*
* 주의!!!
* ?> 기호 다음에 탭 문자열 삽입 되었음!!!
*/
?>
index.html파일을 작성합니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script type="text/javascript" src="jquery-3.2.1.min.js"></script>
<script>
function getData() {
$.ajax({
url: "test.php",
type: "POST",
data: {password: '123'},
success: function (result) {
console.log(result);
if(result == '성공') {
alert('비번 통과 성공!');
} else {
alert('비번 통과 실패!'); // 왜 test.php에서는 '성공'문자열을 리턴해주는데 여기에 걸릴가??????????????????????
}
}
});
}
$(document).ready(function() {
getData(); // test.php에 요청
});
</script>
</head>
<body>
</body>
</html>
이제 웹 브라우저에서 http://localhost/sample/index.html 링크 테스트합니다.
당연히 '성공' 값이 리턴되어 '비번 통과 성공!' 메시지 뜰것이라 믿는 분 계실겁니다.
그런데 실제 보면 test.php가 출력한 값은 빈 행 3개와 뒤끝에 탭이 하나 더 추가된 문자열 즉
'성공'
로, 우리가 원하는 결과값의 앞과 뒤에 빈 행과 탭이 추가되었습니다.
꼭 ajax로 요청보내서 리턴값을 확인해보세요.
예를 통해 보는것 처럼, php 끝 태그 ?> 다음에 눈에는 보이지 않는 공백, 행바꾸기, 탭 등이 있다면 최종 출력값에 이 공백, 행바꾸기 같은것들이 함께 삽입되어 리턴됩니다.
위의 예에서 '성공' 문자열이 리턴 되었지만 사실상 그 앞에 빈 행이 추가되었기 때문에 if(result == '성공') 결과값 비교가 실패하여 alert('비번 통과 실패!');가 작동하게 됩니다.
이렇게 우리는 ?> 태그 다음에 삽입된 공백이나 행바꾸기, 탭 등이 얼마나 큰 허점을 발생시키는지 알게 되었습니다.
php개발과정에 이 문제를 소홀히 하시면 도무지 알수 없는 결과에 당황해져 그 디버깅에 아까운 시간 소모하시게 됩니다.
저도 이런 문제 한번 당했는데, 호상 연동하는 파일들이 너무 많으니 어디서 문제가 발생하고 있는지 몰라서, 끝내 찾아내지 못하구, 결과값을 리턴하기 전에 ob_end_clean()함수를 써서 모면했더랬는데... 바로 이 문제였거든요, 그래서 차후로는 절대 php 끝 기호 ?> 을 망탕 쓰지 않습니다.
php는 php코드로만 작성된 파일에서 끝 기호 ?> 가 없으면 자동적으로 코드마감을 인지하여 처리함으로써 개발자들이 위의 문제에 집중하지 않도록 해줍니다.
그누보드가 바로 이 허점 소홀히 하는거 같아요.
1000개 이상이나 되는 php파일들이 모두 ?> 기호를 사용하였고, ?> 기호 다음에 빈 행이 들어간것도 많고요...
ajax기능도 사용했는데 위의 예처럼 된 부분 있으면 정말 안타까운 문제를 당하고 맙니다.
때문에 그누보드의 모든 php코드파일들 전부 이 문제 고려해서 시급히 수정할것을 정중히 제의드리는 바입니다.
/theme/basic/head.php 파일처럼 php코드와 html, 자바스크립트가 엉킨 코드파일은 이 문제 제기되지 않으니 염려마시고요, 오직 php코드만으로 작성된 코드파일들은 php 끝 기호 ?> 를 제거함이 깨끗한 코드품질을 담보하는것이라 얘기마치게 됩니다.
그리고 그누보드 아름답게 확장하시는 모든 개발자분들도 위의 규칙 고려하여 배포해주세요.
마지막까지 보아주신 여러분께 감사드립니다.
댓글 19개
저도 PHP만 있는 경우 ?>은 생략합니다.
뭐, 저는 phpcs 쓰고 있어서 알아서 잡아주긴 하지만요.
XSS 필터
[code]
public function setXSS($data)
{
$data = str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
do {
$Temporary = $data;
$data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
} while ($Temporary !== $data);
return trim($data);
}
[/code]
뭐, 저는 phpcs 쓰고 있어서 알아서 잡아주긴 하지만요.
XSS 필터
[code]
public function setXSS($data)
{
$data = str_replace(array('&','<','>'), array('&amp;','&lt;','&gt;'), $data);
$data = preg_replace('/(&#*\w+)[\x00-\x20]+;/u', '$1;', $data);
$data = preg_replace('/(&#x*[0-9A-F]+);*/iu', '$1;', $data);
$data = html_entity_decode($data, ENT_COMPAT, 'UTF-8');
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=[\x00-\x20]*([`\'"]*)[\x00-\x20]*j[\x00-\x20]*a[\x00-\x20]*v[\x00-\x20]*a[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2nojavascript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*v[\x00-\x20]*b[\x00-\x20]*s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:#iu', '$1=$2novbscript...', $data);
$data = preg_replace('#([a-z]*)[\x00-\x20]*=([\'"]*)[\x00-\x20]*-moz-binding[\x00-\x20]*:#u', '$1=$2nomozbinding...', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?expression[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?behaviour[\x00-\x20]*\([^>]*+>#i', '$1>', $data);
$data = preg_replace('#(<[^>]+?)style[\x00-\x20]*=[\x00-\x20]*[`\'"]*.*?s[\x00-\x20]*c[\x00-\x20]*r[\x00-\x20]*i[\x00-\x20]*p[\x00-\x20]*t[\x00-\x20]*:*[^>]*+>#iu', '$1>', $data);
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
do {
$Temporary = $data;
$data = preg_replace('#</*(?:applet|b(?:ase|gsound|link)|embed|frame(?:set)?|i(?:frame|layer)|l(?:ayer|ink)|meta|object|s(?:cript|tyle)|title|xml)[^>]*+>#i', '', $data);
} while ($Temporary !== $data);
return trim($data);
}
[/code]
게시글 목록
| 번호 | 제목 |
|---|---|
| 24318 | |
| 24317 | |
| 24315 | |
| 24309 | |
| 24294 | |
| 24293 | |
| 24277 | |
| 24262 | |
| 24260 | |
| 24253 | |
| 24251 | |
| 24236 | |
| 24233 | |
| 24228 | |
| 24226 | |
| 24221 | |
| 24214 | |
| 24203 | |
| 24201 | |
| 24199 | |
| 24196 | |
| 24195 | |
| 24194 | |
| 24192 | |
| 24191 | |
| 24187 | |
| 24185 | |
| 24183 | |
| 24172 | |
| 24168 |
댓글 작성
댓글을 작성하시려면 로그인이 필요합니다.
로그인하기