如何保护 php 脚本?
Posted
技术标签:
【中文标题】如何保护 php 脚本?【英文标题】:How to secure php scripts? 【发布时间】:2014-10-10 19:46:14 【问题描述】:如果我有一个对 php 脚本的 AJAX 调用,像这样(使用 jQuery)
$.ajax(url: "../myscript.php");
myscript
看起来像这样:
<?php
//code that does something to db
?>
我想知道如何防止用户只是去 example.com/myscript.php 执行脚本。
【问题讨论】:
@Fred-ii- 那么$.ajax
应该怎么碰它?
如果“ajax”可以得到它,任何东西都可以。您需要查看action tokens、身份验证/权限以及最大请求阻塞的请求日志记录。
@juan-sebastian-lozano-muñoz:考虑到每个用户都会去提交给example.com/myscript.php
。它总是可能的,并且将会是。黄金法则是:永远不要信任用户,所以你只需采取应对来自普通 html 表单的数据的对策(它本身是可修改的,例如使用右键单击 -> 检查元素或通过像 ZAP 这样的修改代理)。
假设myscript.php
只是另一个网页并像其他网页一样保护它
myscript.php 是做什么的?也许有一种方法可以做你想做的事,而不必信任客户。 (某种服务器端代码完全取决于 php 应该做什么。)
【参考方案1】:
Ajax 查询只是用户查询
每个 XmlHTTP 请求都可以重放和篡改(只需检查您喜欢的浏览器控制台,捕获 POST 或 GET 请求并检查是否有重放选项),您也可以尝试Live HTTP Headers 模块(或更多)并捕获任何东西都可以重播。
因此,如果您在应用程序中设置了一个入口点,任何人都可以尝试访问它并在那里注入一些不好的东西。
请注意,他们还可以更改其请求中的任何 HTTP 标头,以更改引荐来源页面或主机标头等任何内容。
不安全的输入
因此,就安全性而言,每个用户的输入都必须被视为不安全(GET 参数、POST 数据、使用的 url——OMG 如此多的应用程序从不过滤传入的数据来自 url 路径 --, cookies, ...)
过滤后的输出
所以你可能想知道“我怎么能用不安全的输入做一些事情?”,嗯......你可以。规则是过滤所有输出。获取输出通道(数据库存储、html 页面、json 响应、csv 文件)并相应地转义您的数据(HTML 的 htmlentites、json 的 json 转义、sql 转义器或 SQL 查询的参数化查询 - 检查libs--),尤其是来自用户输入的部分,如前所述,它们确实不安全。
访问控制
现在您的主要问题是访问控制,您有一个入口点,您可以在其中执行一些数据库操作,并且您不希望任何人访问该入口点并执行操作。
要做的几件事:
确保这不是一个 GET 入口点(只有 POST、PUT、DELETE HTTP 操作应该对数据库执行修改),这将防止以后在图像标签中使用此 url,在没有用户交互的情况下加载操作。李> 管理一个用户会话,使用cookies(PHP 为你做这件事)你可以在几个HTTP 请求之间共享一些数据,这称为会话。用户 cookie 将用于加载服务器端会话存储,其中包含重要数据,例如 我的用户是匿名用户还是连接用户?。这是标识部分。 管理登录注销页面以获取身份验证部分,这些页面将为会话提供登录状态。对于一个简单的解决方案,您还可以检查 HTTP 基本身份验证(.htpasswd 文件),它也适用于 ajax,但切勿使用没有 SSL 的 HTTP 基本身份验证。这种 Http 身份验证模式将管理标识和身份验证部分。 以您想要的方式管理 ACL(访问控制列表),并使用它来决定当前用户是否可以访问您的 ajax 页面(您从会话中获取用户)。如果没有,请发送 403 HTTP 响应。公共访问
现在,如果您应该运行的“数据库”内容与任何用户权限无关,但您只是想防止滥用它,例如统计 ajax 查询,执行计数器增量,每个用户都应该调用至少一次。在这种情况下,您会遇到一些问题。防止滥用公共入口点非常困难(想想保护网站免受 DOS 和 DDOS 攻击是多么困难)。您必须构建一个基于应用程序的功能系统,例如在用户页面中生成唯一令牌并检查此令牌是否仅使用一次(但来自代理的数千名用户可能会使用匿名页面缓存),也许您必须记录用户 IP 并通过 IP 限制令牌的使用(但某些用户可能共享相同的 IP),或者您可能必须使用 ajax 将唯一令牌发送给用户。
我们可以谈论很多事情,但这取决于你想要做的事情。重要的是:
永远不要相信用户输入 过滤输出 管理会话和 ACL 永远不要认为任何事情都是隐藏的,没有这样的事情。【讨论】:
【参考方案2】:这里的一些答案可以让您大致了解问题背后的概念,让我给您一个更务实的方法(不过,您至少应该阅读并理解其他人对此事的看法!)。
您只需要问自己:您的应用是否必须强制要求控制对 myscript.php 的所有请求?
如果是这样那么您需要使用某种令牌:您创建一个令牌并将其发送到客户端(浏览器),然后浏览器必须发送回该令牌并检查它是否匹配在做一些动作之前:
<?php
// somefile.php (this file serves the page that contains your AJAX call)
session_start();
//...
$_SESSION['token'] = createNewToken(); // creates unique tokens
//add the token as a JS variable and send it back in your AJAX CALL
// some where you'll have something similar to this:
<script>
var token = <?php echo $_SESSION['token'] ?>;
$.ajax(
url: "myscript.php",
data: form_data, // include the token here!
//...
)
然后在你的脚本中:
<?php
// myscript.php
session_start();
// you can check if it's an AJAX call, if the user is logged and then the token:
if (!isset($_SESSION['token'))
header("HTTP/1.0 403 Forbidden");
die("Direct access not allowed!");
// Assuming your AJAX is a POST though you didn't tell us
if (!isset($_POST['token'] || $_POST['token'] != $_SESSION['token'])
header("HTTP/1.0 400 Bad request");
die("You didn't provide a valid token!");
// do something with your DB
否则您只需要检查用户是否已登录,就像您通常对其余脚本所做的那样:
<?php
// myscript.php
session_start();
// Check if logged in user
if (!isset($_SESSION['loggedIn']) || !$_SESSION['loggedIn'])
header("HTTP/1.0 403 Forbidden");
die("You need to be logged in!");
// Do something with your DB
总结
使用第一种方法允许更受控制的访问,因为您强制用户发送普通用户不会拥有的秘密(令牌,在每个请求中都会有所不同)(如果其他用户获得令牌,那么你有更大的问题,比如会话劫持)。请注意,此方法可防止用户在多个选项卡/不同浏览器上打开,因为只会保存最后一个令牌。为了避免你有this fantastic answer on SO
另一方面,第二种方法允许(登录的)用户直接请求您的 myscript.php,但也许您不需要阻止这种情况(如果您需要,只需使用第一种方法)。请注意,您不会遇到多个选项卡/不同浏览器的问题,因为您只会检查用户是否已登录。
【讨论】:
+1 在您给出答案之前,我实际上最终对所有脚本使用了第一种方法,并将其与第二种方法结合用于需要登录的脚本!所以,很好的答案。【参考方案3】:如何防止用户只去example.com/myscript.php 执行脚本
从安全角度来看,AJAX 调用与访问该 URL 的用户相同。也就是说,人类用户和您用来进行 AJAX 调用的脚本是同一个安全主体的一部分。如果您不信任有权访问 PHP 脚本的用户,那么您也无法信任在用户控制的计算机上运行的 javascript。
那么在什么情况下可以有单独的安全主体?例如,您可以只在某种防篡改信息亭上部署客户端 JavaScript。这样,您可以在信息亭中存储一个秘密值,与服务器共享。信息亭将在每个请求中发送秘密值以供服务器验证。
但是,如果您出于可用性原因这样做,以防止 意外 调用脚本,那么是的,也许可以尝试 Dirk Pitt 链接到的一件事。
【讨论】:
以上是关于如何保护 php 脚本?的主要内容,如果未能解决你的问题,请参考以下文章
有人可以将来自不同主机的表单数据发送到我的 PHP 脚本,该脚本将获取的数据插入 MySQL 吗?如果是这样,我们如何保护它?