HTML과 PHP 만 사용하여 XSS (교차 사이트 스크립팅)를 방지하려면 어떻게해야합니까?
이 주제에 대한 다른 많은 게시물을 보았지만 실제로 XSS를 방지하는 방법을 명확하고 간결하게 설명하는 기사를 찾지 못했습니다.
HTML과 PHP 만 사용하여 XSS (교차 사이트 스크립팅)를 방지하려면 어떻게해야합니까?
이 주제에 대한 다른 많은 게시물을 보았지만 실제로 XSS를 방지하는 방법을 명확하고 간결하게 설명하는 기사를 찾지 못했습니다.
답변:
기본적으로 htmlspecialchars()
사용자 입력에서 온 브라우저로 무언가를 출력 하려면이 기능을 사용해야합니다 .
이 기능을 사용하는 올바른 방법은 다음과 같습니다.
echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');
Google Code University에는 웹 보안에 대한 다음과 같은 교육용 비디오도 있습니다.
htmlspecialchars()
.
내가 가장 좋아하는 OWASP 참조 중 하나는 사이트 간 스크립팅 설명입니다. 많은 XSS 공격 경로가 있지만 다음 규칙 중 대다수가 대부분의 공격을 방어 할 수 있기 때문입니다!
이것은 PHP 보안 요령 시트입니다
가장 중요한 단계 중 하나는 사용자 입력을 처리하여 브라우저로 다시 렌더링하기 전에 사용자 입력을 삭제하는 것입니다. PHP에는 사용할 수있는 " 필터 "기능이 있습니다.
XSS 공격의 일반적인 형식은 사용자에 대한 악의적 인 의도가 포함 된 일부 오프 사이트 Javascript에 대한 링크를 삽입하는 것입니다. 자세한 내용은 여기를 참조 하십시오 .
또한 사이트를 테스트하고 싶을 것입니다. Firefox 애드온 XSS Me를 추천 해드립니다 .
선호도 순서대로 :
{{ var|e('html_attr') }}
htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)
하고 문서의 나머지 부분과 동일한 문자 집합을 사용해야합니다 $charset
. 대부분의 경우 'UTF-8'
원하는 문자 세트입니다.또한 input이 아닌 output에서 이스케이프 해야합니다 .
오프라인으로 전환되는 SO 설명서 베타의 통합 참조로이를 교차 게시합니다.
크로스 사이트 스크립팅은 웹 클라이언트가 의도하지 않은 원격 코드 실행을 의미합니다. 웹 응용 프로그램은 사용자의 입력을 받아 웹 페이지에서 직접 출력하는 경우 XSS에 노출 될 수 있습니다. 입력에 HTML 또는 JavaScript가 포함 된 경우 웹 클라이언트가이 컨텐츠를 렌더링 할 때 원격 코드를 실행할 수 있습니다.
예를 들어, 타사에 JavaScript 파일이 포함 된 경우 :
// http://example.com/runme.js
document.write("I'm running");
그리고 PHP 어플리케이션은 전달 된 문자열을 직접 출력합니다 :
<?php
echo '<div>' . $_GET['input'] . '</div>';
확인되지 않은 GET 매개 변수에 포함 된 <script src="http://example.com/runme.js"></script>
경우 PHP 스크립트의 출력은 다음과 같습니다.
<div><script src="http://example.com/runme.js"></script></div>
타사 JavaScript가 실행되고 웹 페이지에 "I running"이 표시됩니다.
일반적으로 클라이언트의 입력을 신뢰하지 마십시오. 모든 GET, POST 및 쿠키 값은 무엇이든 될 수 있으므로 유효성을 검사해야합니다. 이러한 값을 출력 할 때는 예상치 못한 방식으로 평가되지 않도록 이스케이프 처리하십시오.
가장 간단한 응용 프로그램에서도 데이터를 이동할 수 있으며 모든 소스를 추적하기가 어려울 수 있습니다. 따라서 항상 출력을 이스케이프 하는 것이 가장 좋습니다 .
PHP는 상황에 따라 출력을 피할 수있는 몇 가지 방법을 제공합니다.
PHPs 필터 기능은 PHP 스크립트에 대한 입력 데이터가 될 수 있도록 소독 또는 검증 에 많은 방법 . 클라이언트 입력을 저장하거나 출력 할 때 유용합니다.
htmlspecialchars
"HTML 특수 문자"를 HTML 인코딩으로 변환 하므로 표준 HTML로 처리 되지 않습니다 . 이 방법을 사용하여 이전 예제를 수정하려면 다음을 수행하십시오.
<?php
echo '<div>' . htmlspecialchars($_GET['input']) . '</div>';
// or
echo '<div>' . filter_input(INPUT_GET, 'input', FILTER_SANITIZE_SPECIAL_CHARS) . '</div>';
출력 :
<div><script src="http://example.com/runme.js"></script></div>
<div>
태그 내부의 모든 것은 브라우저에서 JavaScript 태그로 해석 되지 않고 간단한 텍스트 노드로 해석됩니다. 사용자는 안전하게 다음을 볼 수 있습니다.
<script src="http://example.com/runme.js"></script>
동적으로 생성 된 URL을 출력 할 때 PHP는 urlencode
유효한 URL을 안전하게 출력 하는 기능을 제공 합니다. 예를 들어, 사용자가 다른 GET 매개 변수의 일부가되는 데이터를 입력 할 수있는 경우 :
<?php
$input = urlencode($_GET['input']);
// or
$input = filter_input(INPUT_GET, 'input', FILTER_SANITIZE_URL);
echo '<a href="http://example.com/page?input="' . $input . '">Link</a>';
악성 입력은 인코딩 된 URL 매개 변수로 변환됩니다.
때로는 HTML 또는 다른 종류의 코드 입력을 보내려고 할 수도 있습니다. 승인 된 단어 목록 (허가 목록)과 승인되지 않은 (블랙리스트) 목록을 유지해야합니다.
OWASP AntiSamy 웹 사이트 에서 사용 가능한 표준 목록을 다운로드 할 수 있습니다 . 각 목록은 특정 종류의 상호 작용 (ebay api, tinyMCE 등)에 적합합니다. 그리고 그것은 오픈 소스입니다.
HTML을 필터링하고 일반적인 경우에 대한 XSS 공격을 방지하고 최소한의 사용은 물론 AntiSamy 목록을 수행하는 라이브러리가 있습니다. 예를 들어 HTML Purifier가 있습니다.
많은 프레임 워크가 XSS를 다양한 방식으로 처리하는 데 도움이됩니다. 직접 롤링하거나 XSS가 우려되는 경우 filter_input_array (PHP 5> = 5.2.0, PHP 7에서 사용 가능)를 활용할 수 있습니다 . 모든 호출은 다른 컨트롤러보다 먼저 통과하기 때문에 일반적으로이 스 니펫을 SessionController에 추가합니다. 데이터와 상호 작용합니다. 이러한 방식으로 모든 사용자 입력이 하나의 중앙 위치에서 삭제됩니다. 프로젝트가 시작될 때 또는 데이터베이스가 중독되기 전에이 작업을 수행하면 출력시 문제가 발생하지 않아야합니다.
/* Prevent XSS input */
$_GET = filter_input_array(INPUT_GET, FILTER_SANITIZE_STRING);
$_POST = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);
/* I prefer not to use $_REQUEST...but for those who do: */
$_REQUEST = (array)$_POST + (array)$_GET + (array)$_REQUEST;
위의 모든 HTML 및 스크립트 태그를 제거 합니다. 화이트리스트를 기반으로 안전한 태그를 허용하는 솔루션이 필요한 경우 HTML Purifier를 확인하십시오 .
데이터베이스가 이미 감염되었거나 출력 시점에 XSS를 처리하려는 경우 OWASP 는에 대한 사용자 정의 래퍼 함수를 생성하고 언제 어디서나 echo
사용자 제공 값을 출력 할 것을 권장 합니다.
//xss mitigation functions
function xssafe($data,$encoding='UTF-8')
{
return htmlspecialchars($data,ENT_QUOTES | ENT_HTML401,$encoding);
}
function xecho($data)
{
echo xssafe($data);
}
다음을 통해 XSS 관련 HTTP 응답 헤더를 설정할 수도 있습니다. header(...)
X-XSS-Protection "1; mode = block"
브라우저 XSS 보호 모드가 활성화되어 있는지 확인하십시오.
콘텐츠 보안 정책 "default-src 'self'; ..."
브라우저 측 콘텐츠 보안을 활성화합니다. CSP (콘텐츠 보안 정책)에 대한 자세한 내용은 다음을 참조하십시오. http://content-security-policy.com/ 특히 인라인 스크립트 및 외부 스크립트 소스를 차단하도록 CSP를 설정하면 XSS에 도움이됩니다.
webapp의 보안과 관련된 유용한 HTTP 응답 헤더에 대해서는 OWASP를 참조하십시오 . https://www.owasp.org/index.php/List_of_useful_HTTP_headers
<?php
function xss_clean($data)
{
// Fix &entity\n;
$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');
// Remove any attribute starting with "on" or xmlns
$data = preg_replace('#(<[^>]+?[\x00-\x20"\'])(?:on|xmlns)[^>]*+>#iu', '$1>', $data);
// Remove javascript: and vbscript: protocols
$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);
// Only works in IE: <span style="width: expression(alert('Ping!'));"></span>
$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);
// Remove namespaced elements (we do not need them)
$data = preg_replace('#</*\w+:\w[^>]*+>#i', '', $data);
do
{
// Remove really unwanted tags
$old_data = $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 ($old_data !== $data);
// we are done...
return $data;
}
preg_replace
대로 사용해서는 안됩니다 eval
. owasp.org/index.php/PHP_Security_Cheat_Sheet#Code_Injection