2012-04-25 6 views
1

나는이 질문을 잠시 후에 게시했으며 사용자 생성 게시물의 링크를 '연결'하는 데 매우 효과적이라고 생각합니다. Linkify Regex Function PHP Daring Fireball Method링크를 구축 할 때 xss 공격을 완화하십시오.

<?php 
if (!function_exists("html")) { 
function html($string){ 
    return htmlspecialchars($string, ENT_QUOTES, 'UTF-8'); 
} 
} 

if (false === function_exists('linkify')): 
    function linkify($str) { 
$pattern = '(?xi)\b((?:(http)s?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))'; 
return preg_replace_callback("#$pattern#i", function($matches) { 
    $input = $matches[0]; 
    $url = $matches[2] == 'http' ? $input : "http://$input"; 
    return '<a href="' . $url . '" rel="nofollow" target="_blank">' . "$input</a>"; 
}, $str); 
} 
endif; 

echo "<div>" . linkify(html($row_rsgetpost['userinput'])) . "</div>"; 

?> 

가 나는 사용자가 링크에 컨텐츠를 생성 삽입하여 보안 위험을 도입 할 수 있다는 우려입니다. 나는 이미 htmlspecialchars($string, ENT_QUOTES, 'UTF-8')으로 데이터베이스에서 오는 사용자 컨텐트를 이스케이프 처리하기 전에 linkify 함수를 실행하고 페이지로 다시 출력하지만 링크 속성을 XSS를 완화하기 위해 특별히 처리해야한다는 OWASP를 읽었습니다. 이 함수는 사용자가 생성 한 내용을 큰 따옴표 안에 넣었으므로 이미 htmlspecialchars($string, ENT_QUOTES, 'UTF-8')으로 이스케이프 처리되었으므로이 기능이 좋다고 생각합니다. 그러나 이것을 확인하기 위해 xss 전문 지식을 가진 사람에게 정말로 감사 할 것입니다. 감사!

+1

신뢰할 수없는 입력을 href, src 또는 다른 URL 기반 특성에 배치하려는 경우 예기치 않은 프로토콜, 특히 자바 스크립트 링크를 가리 키지 않도록 유효성을 검사해야합니다. 그러면 URL은 다른 모든 데이터와 마찬가지로 디스플레이 컨텍스트를 기반으로 인코딩되어야합니다. 예를 들어, HREF 링크의 사용자 중심 URL은 속성 인코딩되어야합니다. 주어진 예제는 자바이다. PHP로 구현하는 방법을 모르는 경우 ... http://code.google.com/p/owasp-esapi-java/source/browse/trunk/src/main/java/org/owasp/esapi/codecs/PercentCodec.java – Jeff

+0

-1 이것은 당황스러운 일이므로 코드를 테스트해야합니다. – rook

+0

전체 코드와 함께 편집 된 질문을 참조하십시오. – Jeff

답변

0

정규 표현식이 http 또는 https 인 URL을 찾고 있습니다. 그 표현은 URL이 아닌 것을 발견하지 못하는 것처럼 상대적으로 안전합니다.

XSS 취약점은 url을 HTML 인수로 이스케이프 처리했을 때 발생합니다. 즉, url이 url 문자열을 조기에 이스케이프 처리 할 수 ​​없다는 것을 확인한 다음 @Rook이 언급 한 html 태그에 추가 속성을 추가해야합니다.

그래서 난 정말 @tobyodavies에 의해 제안 등의 XSS 공격이 다음 코드를 수행 할 수있는 방법을 방법을 생각할 수 없다,하지만 뭔가 다른 않습니다를 urlencode없이 :

$pattern = '(?xi)\b((?:(http)s?://|www\d{0,3}[.]|[a-z0-9.\-]+[.][a-z]{2,4}/)(?:[^\s()<>]+|\(([^\s()<>]+|(\([^\s()<>]+\)))*\))+(?:\(([^\s()<>]+|(\([^\s()<>]+\)))*\)|[^\s`!()\[\]{};:\'".,<>?«»“”‘’]))'; 
return preg_replace_callback("#$pattern#i", function($matches) { 
    $input = $matches[0]; 
    $url = $matches[2] == 'http' ? $input : "http://$input"; 
    return '<a href="' . htmlspecialchars($url) . '" rel="nofollow" target="_blank">' . "$input</a>"; 
}, $str); 

참고 나는 또한이 그 http 접두어를 확인하기위한 작은 바로 가기를 추가했습니다.

생성하는 앵커 링크가 안전합니다.

그러나 나머지 텍스트도 살균해야합니다. 나는 모든 HTML을 허용하고 모든 HTML을 일반 텍스트로 표시하고 싶지 않다고 가정합니다.

+0

Thanks @d_inevitable. 나는 당신이 원래 linkify 함수가 당신 것이기 때문에 이것을 보길 바랬다. 불행히도 위의 ($ mathes -> $ matches에 typo를 수정 한 후) linkify 함수가 더 이상 작동하지 않는다. 예를 들어 'www.google.com'이라는 입력 된 텍스트를 클릭하면 링크가 https://www.mysite.com/directory/http%3A%2F%2Fwww.google.com으로 이동합니다. 이것은 원래 $ 패턴 정규 표현식이 더 이상 urlencode 문자와 비교할 수 없기 때문입니까? 사용자 생성 콘텐츠가 큰 따옴표 안에 있으므로 원래 'linkify'함수로 충분하다고 생각하십니까? – Jeff

+0

예 원본은 충분하지만 효율성은 떨어집니다. 내가 한 것처럼 패턴을 바꿨 니? http :'(http)'주위의 대괄호. –

+0

실제로 문제를 발견했습니다. 프로토콜을 사용해서는 안되는 URL 인코딩입니다. 작동하게 편집 할 것입니다. –

1

첫 번째 데이터는 NEVER은 데이터베이스에 들어가기 전에 반드시 이스케이프해야합니다. 이것은 매우 심각한 실수입니다. 이것은 안전하지 않을뿐만 아니라 기능을 손상시킵니다. 문자열 값을 체인화하면 데이터가 손상되고 문자열 비교에 영향을줍니다. 이 접근법은 XSS is an output problem이므로 안전하지 않습니다. 데이터베이스에 데이터를 삽입 할 때 페이지에 표시되는 위치를 알 수 없습니다. 심지어 경우 예를 들어,이 기능은 다음 코드는 XSS에 여전히 취약 여기서 예를 들어

: 정규 표현식의 측면에서

<a href="javascript:alert(1)" \> 

. 나의 초기 반응은 음, 이것은 끔찍한 생각이다. 그것의 이 어떻게 작동하고 NOT 연산자의 과도한 사용을 위해을 가정했는지에 대한 아무런 의견도없고, 블랙리스트는 화이트리스트보다 항상이 더 입니다.

그래서 나는 Regex Buddy을로드 약 3 분에 나는이 입력으로 정규식을 우회 :

https://test.com/test'onclick='alert(1);// 

어떤 개발자가 vulnerably을 쓰고 싶어, 그래서 그들은 프로그래머가 생각하는 방법의 고장으로 인해 발생 그의 응용 프로그램이 작동하고 있으며, 실제로 어떻게 작동하는지 보여줍니다. 이 경우 나는이 정규식을 테스트하지 않았다고 가정하고 문제의 총체적인 지나친 단순화를 가정합니다.

HTMLPurifer는 HTML을 지우도록 고안된 PHP 라이브러리이며, THOUSANDS 정규 표현식으로 구성됩니다. 매우 느리고 정기적으로 우회됩니다. 따라서이 길로 가면 정기적으로 업데이트하십시오.

이 결함을 수정하는 측면에서 나는 htmlspecialchars($string, ENT_QUOTES, 'UTF-8')을 사용하여 최선을 다한 다음 'http'로 시작하는 문자열을 시행해야한다고 생각합니다. HTML 인코딩은 이스케이프 (escaping)의 한 형태이며 값이 자동으로 디코딩되어 URL이 변조되지 않습니다.또한 다음 HTML

return '<a href="' . htmlspecialchars(urlencode($url)) . '" rel="nofollow" target="_blank">' . "$input</a>"; 

하지만 브라우저를 부호화한다 기술적

return '<a href="' . urlencode($url) . '" rel="nofollow" target="_blank">' . "$input</a>"; 

: 데이터 속성 들어가는 때문에

1

, URL (또는 백분율)로 인코딩되어야 나는 치료에 대해 안다. 그러므로 아무도 그것을하지 않는다. 당신이 이미이 단계를 수행하고있는 것처럼 들린다. do not

+0

이러한 접근법 중 어느 것도 유효한 http 링크를 생성하지 않습니다. 이 접근 방식은 자멸합니다. – rook

+0

감사합니다. @tobyodavies. 나는 당신이 바른 길에 있다고 생각합니다. 나는 그것을 일찍 시도했습니다. 불행히도 urlencoded url은 preg_replace_callback 함수에서 링크를 결정하는 Regex와 더 이상 일치하지 않기 때문에 'linkify'함수를 사용하지 않습니다. 불행히도, 그것은 내 머리를 조금 넘기고 ... 가능한지 확실하지 않습니다. – Jeff

+0

@ 잘못된 URL이 URL 인코딩을 벗어날 수 있습니다. 그것은 무의미하게 끝날 수 있습니다,하지만 그것은 항상 합법적 일 것이고 JS 링크가 될 수 없거나 DOM에 부작용이있을 수 있습니다.) – tobyodavies

0

첫째, PHP 문서로 states 반드시 htmlspecialchars 만 탈출 "가 '&'(앰퍼샌드) '&' '"'(큰 따옴표) ENT_NOQUOTES가 설정되지 않은 '"을'이된다. ENT_QUOTES가 설정된 경우에만 '' '(작은 따옴표)가'' '(또는 ')이됩니다. . '<은'(이하) 자바 스크립트 " '<은' 는 '>'(보다 큰) '>' 을하게된다 : 아직 일반 프로그래밍에 사용되는, 그래서 왜 : 탈출하지 않는 것은 나를 넘어

.

둘째,! html이 입력 될 것으로 생각되는 문자 만 기대하고 입력 할 수 있고 유효한 문자로 표시되지 않는 경우 u tf-8 character set 및 다른 모든 문자 세트는 동일한 문자에 대해 여러 개의 표현을 지원합니다. , 거짓 진술은 0-9와 az를 허용하므로 여전히 base64 characters에 대해 걱정해야합니다. 코드를 좋은 시도라고 부르지 만, 정제를해야합니다. 즉, 사람들이 여전히 사용할 수있는 htmlpurifier을 사용할 수 있습니다. 바이 패스 에스. 대부분의 프로그래머가 왜 그렇게해야하는지 이해하지 못하기 때문에 htmlspecialchars에서 문자 집합을 설정하는 것이 좋습니다.