HTML / PHP로 XSS를 방지하는 방법은 무엇입니까?


256

HTML과 PHP 만 사용하여 XSS (교차 사이트 스크립팅)를 방지하려면 어떻게해야합니까?

이 주제에 대한 다른 많은 게시물을 보았지만 실제로 XSS를 방지하는 방법을 명확하고 간결하게 설명하는 기사를 찾지 못했습니다.


3
이것은 사용자 입력을 HTML 속성으로 사용하려는 경우에는 해결되지 않습니다. 예를 들어 이미지의 소스 URL입니다. 흔한 경우는 아니지만 잊을 수있는 쉬운 경우입니다.
Michael Mior

@MichaelMior 여기에 XSS href또는 srcHTML 속성 을 방지하는 솔루션이 있습니다 : stackoverflow.com/questions/19047119/…
baptx

XSS를 설명하고 다른 언어 (PHP 포함)로 XSS를 방지하는 방법을 설명 하는 좋은 기사가 있습니다 .
XCore

답변:


296

기본적으로 htmlspecialchars()사용자 입력에서 온 브라우저로 무언가를 출력 하려면이 기능을 사용해야합니다 .

이 기능을 사용하는 올바른 방법은 다음과 같습니다.

echo htmlspecialchars($string, ENT_QUOTES, 'UTF-8');

Google Code University에는 웹 보안에 대한 다음과 같은 교육용 비디오도 있습니다.


7
@TimTim : 대부분의 경우 예. 그러나 HTML 입력을 허용해야 할 때 조금 까다로워
Alix Axel

@Alix Axel, htmlspecialchars 또는 htmlpurifier.org 를 사용하는 당신의 대답은 무엇입니까?
TimTim

3
HTML 입력을 수락해야하는 경우 HTML Purifier를 사용하십시오 (사용하지 않는 경우) htmlspecialchars().
Alix Axel

9
htmlspecialchars 또는 htmlentities? 여기를 확인하십시오 stackoverflow.com/questions/46483/…
kiranvj

4
대부분의 경우 정확하지만 그렇게 간단하지는 않습니다. 신뢰할 수없는 문자열을 HTML, Js, Css에 넣고 신뢰할 수없는 HTML을 HTML에 넣으십시오. 이것 좀 봐 : owasp.org/index.php/…
청동 남자

41

내가 가장 좋아하는 OWASP 참조 중 하나는 사이트 간 스크립팅 설명입니다. 많은 XSS 공격 경로가 있지만 다음 규칙 중 대다수가 대부분의 공격을 방어 할 수 있기 때문입니다!

이것은 PHP 보안 요령 시트입니다


7
나도 .. 이것은 XSS 필터 회피 치트 시트 owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet

1
정확히 XSS는 아니지만 XSS와 CSRF가 일반적으로 혼합되어 있고 둘 다 실제로 위험하다고 생각합니다. owasp.org/index.php/…
Simon

2
이 페이지는 더 이상 존재하지 않습니다
Mazzy


15

가장 중요한 단계 중 하나는 사용자 입력을 처리하여 브라우저로 다시 렌더링하기 전에 사용자 입력을 삭제하는 것입니다. PHP에는 사용할 수있는 " 필터 "기능이 있습니다.

XSS 공격의 일반적인 형식은 사용자에 대한 악의적 인 의도가 포함 된 일부 오프 사이트 Javascript에 대한 링크를 삽입하는 것입니다. 자세한 내용은 여기를 참조 하십시오 .

또한 사이트를 테스트하고 싶을 것입니다. Firefox 애드온 XSS Me를 추천 해드립니다 .


입력을 정확하게 삭제해야하는 것은 무엇입니까? 주의해야 할 특정 문자 / 문자열이 있습니까?
TimTim

27
@TimTim-아니요. 모든 사용자 입력항상 본질적으로 적대적인 것으로 간주 되어야합니다 .
zombat

또한 내부 데이터 (직원, 시스템 관리자 등)는 안전하지 않을 수 있습니다. 해석과 함께 표시되는 데이터 (로그 날짜 및 사용자)를 식별하고 모니터해야합니다.
Samuel Dauzon

9

선호도 순서대로 :

  1. 템플릿 엔진 (예 : Twig, Smarty, Blade)을 사용하는 경우 상황에 맞는 이스케이프를 제공하는지 확인하십시오. 나는 나뭇 가지가하는 경험을 알고 있습니다.{{ var|e('html_attr') }}
  2. HTML을 허용하려면 HTML Purifier를 사용하십시오 . Markdown 또는 ReStructuredText 만 수락한다고 생각하더라도 HTML에 이러한 마크 업 언어 출력을 정제하려고합니다.
  3. 그렇지 않으면 사용 htmlentities($var, ENT_QUOTES | ENT_HTML5, $charset)하고 문서의 나머지 부분과 동일한 문자 집합을 사용해야합니다 $charset. 대부분의 경우 'UTF-8'원하는 문자 세트입니다.

또한 input이 아닌 output에서 이스케이프 해야합니다 .


7

오프라인으로 전환되는 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 스크립트에 대한 입력 데이터가 될 수 있도록 소독 또는 검증많은 방법 . 클라이언트 입력을 저장하거나 출력 할 때 유용합니다.

HTML 인코딩

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>&lt;script src=&quot;http://example.com/runme.js&quot;&gt;&lt;/script&gt;</div>

<div>태그 내부의 모든 것은 브라우저에서 JavaScript 태그로 해석 되지 않고 간단한 텍스트 노드로 해석됩니다. 사용자는 안전하게 다음을 볼 수 있습니다.

<script src="http://example.com/runme.js"></script>

URL 인코딩

동적으로 생성 된 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 매개 변수로 변환됩니다.

특수한 외부 라이브러리 또는 OWASP AntiSamy 목록 사용

때로는 HTML 또는 다른 종류의 코드 입력을 보내려고 할 수도 있습니다. 승인 된 단어 목록 (허가 목록)과 승인되지 않은 (블랙리스트) 목록을 유지해야합니다.

OWASP AntiSamy 웹 사이트 에서 사용 가능한 표준 목록을 다운로드 할 수 있습니다 . 각 목록은 특정 종류의 상호 작용 (ebay api, tinyMCE 등)에 적합합니다. 그리고 그것은 오픈 소스입니다.

HTML을 필터링하고 일반적인 경우에 대한 XSS 공격을 방지하고 최소한의 사용은 물론 AntiSamy 목록을 수행하는 라이브러리가 있습니다. 예를 들어 HTML Purifier가 있습니다.


5

많은 프레임 워크가 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);
}

2

다음을 통해 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


1
<?php
function xss_clean($data)
{
// Fix &entity\n;
$data = str_replace(array('&amp;','&lt;','&gt;'), array('&amp;amp;','&amp;lt;','&amp;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;
}

5
입력에 사용 된 preg_replace대로 사용해서는 안됩니다 eval. owasp.org/index.php/PHP_Security_Cheat_Sheet#Code_Injection
CrabLab

0

사용 htmlspecialcharsPHP. HTML에서는 다음을 사용하지 마십시오.

element.innerHTML = “…”; element.outerHTML = “…”; document.write(…); document.writeln(…);

여기서 사용자var제어합니다 .

또한 분명히 피 eval(var)하십시오.이 중 하나를 사용해야하는 경우 JS 이스케이프 를 시도 하고 HTML을 이스케이프 처리하고 더 많은 작업을 수행해야 할 수도 있지만 기본 사항으로는 충분합니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.