8

我正在开发一个 PHP Web 应用程序,我想为应用程序提供更高的安全性,以便没有人可以轻易破坏该功能。

关于我的问题的简要说明:在一个模块中,有一个阶段我正在检查请求的来源(该请求的来源)

目前,我正在使用HTTP_REFERRER变量(在 php 中可用)。我正在使用一个特定的 URL(例如http://www.example.com/test.php)检查这个变量值。如果存在完全匹配,那么只有我在呼吁采取进一步行动。

我对上述方法有点困惑,我应该使用 HTTP_REFERRER 还是检查 IP 地址(如果请求来自任何特定的 IP 地址,则为有效请求)?

我还想知道提供安全性的更好方法。

有没有人有想法然后请分享?

提前致谢

4

3 回答 3

7

网络安全第一课:永远不要相信用户输入。当我说从不时,我的意思是从不。;) 包括 PHP 中的 HTTP_REFER var,它很容易被 http 标头破坏(来源: http: //www.mustap.com/phpzone_post_62_how-to-bypass-the-referer-se

检查源的一种可能解决方案是使用表单令牌(csrf 保护):http ://www.thespanner.co.uk/2007/04/12/one-time-form-tokens/但不是那么安全要么,而且只有你自己的来源才有可能。

一个简单的 CSRF(跨站请求伪造)保护示例:(因此很简单。有关更安全/稳健的解决方案,请参阅 The Rook 的答案)

1)在您的表单页面中,创建某种令牌并放入您的会话和隐藏的表单字段中:

<?php
    session_start();
    $csrfToken = md5(uniqid(mt_rand(),true)); // Token generation updated, as suggested by The Rook. Thanks!

    $_SESSION['csrfToken'] = $token;
?>
<form action="formHandler.php">
   <input type="hidden" name="csrfKey" value="<?php echo $csrfToken ?>" />
</form>

2)在您的表单处理程序中检查令牌是否有效。

<?php
   session_start();
   if($_POST['csrfKey'] != $_SESSION['csrfKey']) {
      die("Unauthorized source!");
   }
?>
于 2010-06-28T13:17:18.417 回答
3

检查HTTP_REFERRERCSRF 是一种有效的保护形式。虽然在您的OWN BROWSER上欺骗这个 HTTP 标头是微不足道的,但在使用 CSRF 的其他人浏览器上欺骗它是不可能的,因为它违反了规则

根据国土安全部的说法,我发现了有史以来最危险的 CSRF 漏洞,并且是有史以来最危险的 1000 个漏洞之一。摩托罗拉使用引用检查修补了这个漏洞,由于内存稀缺,这种保护方法在嵌入式网络硬件上很常见。

A more common and more secure method is to store a Cryptographic nonce inside a $_SESSION variable and check this for each sensitive request. An easy approach is to use POST for all sensitive requests (like changing your password) and make sure this Cryptographic nonce is valid for all posts in a php header file, if it isn't valid then unset($_POST);. This method works because although an attacker can force your browser into SENDING GET/POST requests he cannot view the RESPONSE, and there for cannot read this token needed to forge the request. This token can be obtained with XSS, so make sure you test your site for xss.

A good method for generating a csrf token is md5(uniqid(mt_rand(),true)); This should be enough entropy to stop CSRF. md5() is used to obscure how the salt is generated. Keep in mind that the current time is not a secret, the attacker knows exactly what time the CSRF request is produced and can narrow down when the session was created. You must assume that the attacker can make many guesses, and in practice this is simple to accomplish by writing a bunch of iframes to the page.

于 2010-06-28T17:56:03.137 回答
2

Treur got it right, but I still want to clarify a few things and provide you with some sources for reference material. As Treur said, NEVER ever trust user input data, that includes all headers sent by the browser.

What you are describing, is a typical Cross-Site Request Forgery attack. Checking the referrer header is not a valid protection against CSRF attacks, since according to the RFC2616 (Hyper Text Transfer Protocol 1.1), the referer header is optional and thus may be omitted by the browser at any time. If you are using SSL, then the referer header is always omitted by browsers. Secondly, it is a user defined value, and thus should not be trusted.

The recommended protection against CSRF attacks is to use the synchronized token pattern. This means that you should create a secret token which is embedded as a hidden field in your form. When the form is posted, you verify that the secret token is present and that it is valid. There are multiple strategies for creating security tokens. I'll describe one way for creating the tokens:

For each action in your application, create a unique action name for them. For example, "delete_user", "add_user" or "save_user_profile". Let's say that the form you described has the action name "foobar". Concatenate the action name with the user's session id and a secret value.

$stringValue = "foobar" . "secret value" . session_id();

To create the security token, create a hash of the concatenated string, you can use sha1 to create the hash. To decrease the risk of brute force attacks, use a larger key in the hash, for example, sha 512.

$secretToken = hash("sha5125", $stringValue);

Set this token in your form's hidden field. When the form is submitted, recreate the token and verify that it matches the one submitted in the form. This token is valid for one user session. One may argue, that there is a window of opportunity where an attacker can reuse the token as it is not regenerated at every request. However, with proper session management strategies, this shouldn't really be a concern.

Like I said, proper session management is necessary. This means that you shouldn't keep the sessions alive to long. Especially session fixation vulnerabilities will undo any CSRF protection measures, as the attacker is then in control of the user session and hence can "predict" the secret tokens.

Here are a couple of links that I recommend you read through:

于 2010-07-09T07:39:59.587 回答