CSRF(Cross-Site Request Forgery)는 공격자가 피해자를 통해 임의의 HTTP 요청을 보낼 수 있도록 하는 공격 방법의 한 유형입니다. 여기서 피해자는 자신도 모르게 공범이며, 모든 위조된 요청은 공격자가 아닌 그 사람에게서 비롯됩니다. 이러한 방식으로는 어떤 요청이 교차 사이트 요청 위조 공격인지 판단하기가 매우 어렵습니다. 실제로 교차 사이트 요청 위조 공격에 대해 예방 조치를 취하지 않으면 애플리케이션이 취약해질 수 있습니다.
아래에서 펜이나 연필을 구매할 수 있는 간단한 앱을 살펴보세요. 인터페이스에는 다음 형식이 포함됩니다.
CODE:
<form action="buy.php" method="POST"> <p> Item: <select name="item"> <option name="pen">pen</option> <option name="pencil">pencil</option> </select><br /> Quantity: <input type="text" name="quantity" /><br /> <input type="submit" value="Buy" /> </p> </form>
공격자는 먼저 애플리케이션을 사용하여 몇 가지 기본 정보를 수집합니다. 예를 들어 공격자는 먼저 양식에 액세스하여 두 가지 양식 요소 항목과 수량을 발견합니다. 또한 항목의 값이 연필 또는 펜이라는 것도 알고 있습니다.
다음 buy.php 프로그램은 양식 제출 정보를 처리합니다.
CODE:
<?php session_start(); $clean = array(); if (isset($_REQUEST['item'] && isset($_REQUEST['quantity'])) { /* Filter Input ($_REQUEST['item'], $_REQUEST['quantity']) */ if (buy_item($clean['item'], $clean['quantity'])) { echo '<p>Thanks for your purchase.</p>'; } else { echo '<p>There was a problem with your order.</p>'; } } ?>
공격자는 먼저 이 형식을 사용하여 동작을 관찰합니다. . 예를 들어, 공격자는 연필을 구매한 후 구매가 성공하면 감사 메시지가 나타날 것이라는 것을 알고 있습니다. 이를 인지한 공격자는 다음 URL에 접속하여 GET을 사용하여 데이터를 제출함으로써 동일한 목적을 달성할 수 있는지 확인하려고 합니다:
http://www.php.cn/
성공하면 이제 공격자는 합법적인 사용자가 방문할 때 구매를 트리거할 수 있는 URL 형식을 갖게 됩니다. 이 경우 공격자는 피해자가 해당 URL을 방문하도록 유도하기만 하면 되기 때문에 교차 사이트 요청 위조 공격을 수행하기가 매우 쉽습니다.
사이트 간 요청 위조 공격을 시작하는 방법에는 여러 가지가 있지만 이미지와 같은 내장된 리소스를 사용하는 것이 가장 일반적입니다. 이 공격이 어떻게 작동하는지 이해하려면 먼저 브라우저가 이러한 리소스를 요청하는 방식을 이해해야 합니다.
http://www.php.cn/ 접속시 (사진 2-1), 브라우저는 먼저 이 URL로 식별되는 리소스를 요청합니다. 페이지의 소스 파일(HTML)을 보면 이 요청의 반환 콘텐츠를 볼 수 있습니다. 브라우저가 반환된 콘텐츠를 구문 분석한 후 Google 로고 이미지가 발견되었습니다. 이 이미지는 HTML img 태그로 표현되며, 태그의 src 속성은 이미지의 URL을 나타냅니다. 그런 다음 브라우저는 이미지에 대한 또 다른 요청을 발행합니다. 두 요청의 유일한 차이점은 URL입니다.
그림 2-1 구글 홈페이지
CSRF 공격은 img 태그를 사용하여 이를 활용할 수 있습니다. 다음 이미지가 있는 웹사이트를 방문해 보세요. 출처 :
위의 원칙에 따라 img 태그를 통해 크로스 사이트 요청 위조 공격이 가능합니다. 방문에 다음이 포함되는지 고려하세요. 다음 소스 코드가 포함된 페이지는 어떻게 되나요?
<img src="http://store.example.org/buy.php?item=pencil&quantity=50" />
buy.php 스크립트는 $_POST 대신 $_REQUEST를 사용하므로 store.example.org 상점에 로그인한 모든 사용자는 이 URL을 요청하여 연필 50개를 구매하게 됩니다.
크로스 사이트 요청 위조 공격의 존재는 $_REQUEST를 권장하지 않는 이유 중 하나입니다.
전체 공격 과정은 그림 2-2와 같다.
그림 2-2. 이미지에 의한 크로스 사이트 요청 위조 공격
이미지를 요청할 때 일부 브라우저는 요청 헤더의 Accept 값을 변경하여 이미지 유형에 더 높은 우선 순위를 부여합니다. 이런 일이 발생하지 않도록 보호 조치가 필요합니다.
你需要用几个步骤来减轻跨站请求伪造攻击的风险。一般的步骤包括使用POST方式而不是使用GET来提交表单,在处理表单提交时使用$_POST而不是$_REQUEST,同时需要在重要操作时进行验证(越是方便,风险越大,你需要求得方便与风险之间的平衡)。
任何需要进行操作的表单都要使用POST方式。在RFC 2616(HTTP/1.1传送协议,译注)的9.1.1小节中有一段描述:
“特别需要指出的是,习惯上GET与HEAD方式不应该用于引发一个操作,而只是用于获取信息。这些方式应该被认为是‘安全’的。客户浏览器应以特殊的方式,如POST,PUT或DELETE方式来使用户意识到正在请求进行的操作可能是不安全的。”
最重要的一点是你要做到能强制使用你自己的表单进行提交。尽管用户提交的数据看起来象是你表单的提交结果,但如果用户并不是在最近调用的表单,这就比较可疑了。请看下面对前例应用更改后的代码:
CODE:
<?php session_start(); $token = md5(uniqid(rand(), TRUE)); $_SESSION['token'] = $token; $_SESSION['token_time'] = time(); ?> <form action="buy.php" method="POST"> <input type="hidden" name="token" value="<?php echo $token; ?>" /> <p> Item: <select name="item"> <option name="pen">pen</option> <option name="pencil">pencil</option> </select><br /> Quantity: <input type="text" name="quantity" /><br /> <input type="submit" value="Buy" /> </p> </form>
通过这些简单的修改,一个跨站请求伪造攻击就必须包括一个合法的验证码以完全模仿表单提交。由于验证码的保存在用户的session中的,攻击者必须对每个受害者使用不同的验证码。这样就有效的限制了对一个用户的任何攻击,它要求攻击者获取另外一个用户的合法验证码。使用你自己的验证码来伪造另外一个用户的请求是无效的。
该验证码可以简单地通过一个条件表达式来进行检查:
CODE:
<?php if (isset($_SESSION['token']) && $_POST['token'] == $_SESSION['token']) { /* Valid Token */ } ?>
你还能对验证码加上一个有效时间限制,如5分钟:
CODE:
<?php $token_age = time() - $_SESSION['token_time']; if ($token_age <= 300) { /* Less than five minutes has passed. */ } ?>
通过在你的表单中包括验证码,你事实上已经消除了跨站请求伪造攻击的风险。可以在任何需要执行操作的任何表单中使用这个流程。
尽管我使用img标签描述了攻击方法,但跨站请求伪造攻击只是一个总称,它是指所有攻击者通过伪造他人的HTTP请求进行攻击的类型。已知的攻击方法同时包括对GET和POST的攻击,所以不要认为只要严格地只使用POST方式就行了。
以上就是PHP安全-跨站请求伪造的内容,更多相关内容请关注PHP中文网(www.php.cn)!