简体   繁体   English

如何保护PHP脚本?

[英]How to secure php scripts?

If I have an AJAX call to a php script, like this (using jQuery) 如果我对php脚本进行AJAX调用,就像这样(使用jQuery)

$.ajax(url: "../myscript.php");

and myscript looks like this: myscript看起来像这样:

<?php
    //code that does something to db
 ?>

I want to know how to prevent a user from just going to example.com/myscript.php to execute the script. 我想知道如何防止用户只是去example.com/myscript.php来执行脚本。

Ajax queries are just user queries Ajax查询只是用户查询

Every XmlHTTP request can be replayed and tampered (just check your favorite browser console, capture the POST or GET requests and check if there is a replay options), you can also try Live HTTP Headers module (or many more) and capture anything to replay it. 每个XmlHTTP请求都可以重放和篡改(只需检查您最喜欢的浏览器控制台,捕获POST或GET请求并检查是否有重播选项),您还可以尝试Live HTTP Headers模块(或更多)并捕获任何内容进行重放它。

So if you set an entry point in your application, anybody can try to access it and inject some bad stuff there. 因此,如果您在应用程序中设置了一个入口点,那么任何人都可以尝试访问它并在那里注入一些不好的东西。

Note that they can also alter any HTTP headers in their requests to alter things like the referrer page or the host header, anything. 请注意,他们还可以更改其请求中的任何HTTP标头,以更改引用页面或主机标头等任何内容。

Insecure Inputs 不安全的输入

So in term of security every user input has to be considered unsafe (GET parameters, POST data, used url -- OMG so much application are never filtering data coming from the url path --, cookies, ...) 因此,在安全性方面,每个用户输入都必须被认为是不安全的 (GET参数,POST数据,使用过的url - OMG,因此很多应用程序永远不会过滤来自url路径的数据 - ,cookies,......)

Filtered output 过滤输出

So you may wonder "How can I do something with insecure inputs?", well ...you can. 所以你可能想知道“我怎么能用不安全的输入做些什么?”,嗯......你可以。 The rule is to filter all the outputs. 规则是过滤所有输出。 Take the output canal (database storage, html page, json response, csv file) and escape your data accordingly (htmlentites for HTML, json escapes for json, sql escaper or parametized queries for SQL queries -- check the libs--), especially the parts coming from the user input, which are really unsafe as stated before. 获取输出管道(数据库存储,html页面,json响应,csv文件)并相应地转义数据 (htmlentites用于HTML,json转义为json,sql escaper或参数化查询用于SQL查询 - 检查libs--),尤其是来自用户输入的部件,如前所述,实际上是不安全的。

Access control 访问控制

Now your main problem here is access control, you have an entry point where you perform some database actions and you do not want anybody to access this entry point and perform actions. 现在您的主要问题是访问控制,您有一个入口点,您可以在其中执行某些数据库操作,并且您不希望任何人访问此入口点并执行操作。

Several things to do: 有几件事要做:

  • ensure this is not a GET entry point (only POST, PUT, DELETE HTTP actions should perform modifications on the database), this will prevent usage of this url in an image tag later, loading the action without user interaction. 确保这不是GET入口点(只有POST,PUT,DELETE HTTP操作应该对数据库执行修改),这将阻止在以后在图像标记中使用此URL,在没有用户交互的情况下加载操作。
  • manage a user session , using cookies (PHP does that for you) you can share some data between several HTTP requests, this is called a session. 管理用户会话 ,使用cookie(PHP为您做到这一点)您可以在多个HTTP请求之间共享一些数据,这称为会话。 The user cookie will be used to load the server-side session storage, containing important data, such as Is my user an anonymous user or a connected one? 用户cookie将用于加载服务器端会话存储,其中包含重要数据,例如我的用户是匿名用户还是已连接的用户? . This is the Identification part. 这是识别部分。
  • manage log-in log-out pages to get the Authentication part, theses pages will feed the session with the logged-in status. 管理登录注销页面以获取身份验证部分,这些页面将以登录状态提供会话。 For a simple solution you can also check for HTTP basic authentication (.htpasswd files), it will also work for ajax, but never use HTTP basic Authentication without SSL. 对于一个简单的解决方案,您还可以检查HTTP基本身份验证(.htpasswd文件),它也适用于ajax,但从不使用没有SSL的HTTP基本身份验证。 This Http auth mode will manage both identification and authentication parts. 此Http身份验证模式将管理身份和身份验证部分。
  • manage ACL (Access Control List), the way you want, and use that to decide if your ajax page can be accessed by the current user (you get the user from the session). 按照您希望的方式管理ACL (访问控制列表),并使用它来决定当前用户是否可以访问您的ajax页面(您从会话中获取用户)。 If not, send a 403 HTTP response. 如果没有,请发送403 HTTP响应。

Public Access 公共访问

Now if your 'database' stuff that should run is not related to any user privilege, but you just want to prevent abuse of it, like, say, a statistical ajax query, doing a counter increment, that every user should call at least once. 现在,如果您应该运行的“数据库”内容与任何用户权限无关,但您只是想防止滥用它,例如统计ajax查询,执行计数器增量,每个用户应至少调用一次。 In this case you will have some problems. 在这种情况下,您将遇到一些问题。 It's very hard to prevent abuse of a public entry point (just think of how hard it is to protect websites from DOS and DDOS). 很难防止滥用公共入口点(只考虑保护网站免受DOS和DDOS的困扰)。 You'll have to build a functional system, application-based, things like generating a unique token in the user page and checking that this token is used only once (but an anonymous page could be used by thousands of users, coming from a proxy cache), maybe you'll have to record user IP and restrict the token usage by IP (but some users may share the same IP), or maybe you'll have to send the unique token to the user using ajax. 您必须构建一个基于应用程序的功能系统,例如在用户页面中生成唯一令牌并检查此令牌仅使用一次(但是来自代理的数千个用户可以使用匿名页面)缓存),也许你必须记录用户IP并通过IP限制令牌使用(但是一些用户可能共享相同的IP),或者你可能必须使用ajax将唯一令牌发送给用户。

We could talk of a lot of things, but that depends on the things you are trying to do. 我们可以谈论很多事情,但这取决于你想要做的事情。 The important thing are: 重要的是:

  • never trust user inputs 从不信任用户输入
  • filter outputs 过滤输出
  • manage sessions and ACL 管理会话和ACL
  • never consider anything as hidden, there's no such thing. 从不认为任何隐藏的东西,没有这样的东西。

Some answers here give you an overview of the concepts behind your question, let me give you a more pragmatic approach (you should at least read and understand what others say about this matter though!). 这里的一些答案让你概述了问题背后的概念,让我给你一个更务实的方法(你至少应该阅读并理解其他人对此事的看法!)。

You just need to ask yourself: Do your app must enforce that all requests to myscript.php should be controlled? 你只需要问自己: 你的应用程序是否必须强制执行对myscript.php的所有请求都应该被控制?

If so then you need to use some sort of token: you create a token and send it to the client (browser), then the browser must send back the token and you check if it matches before doing some action: 如果是这样,那么你需要使用某种令牌:你创建一个令牌并将其发送到客户端(浏览器),然后浏览器必须发回令牌并在执行某些操作之前检查它是否匹配:

<?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!
    //...
  })

And then in your script: 然后在你的脚本中:

<?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

Otherwise you just need to check if the user is logged as you would normally do with the rest of your scripts: 否则,您只需要检查用户是否按照通常对其余脚本执行的操作进行记录:

<?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

TO SUM UP 总结一下

Using the first method allows a more controlled access as you force the user to send a secret (the token, which will be different in every request) that a normal user won't have (if some other user gets the token, then you have bigger problems like session hijacking). 使用第一种方法允许更加受控制的访问,因为您强制用户发送一个普通用户不会拥有的秘密(令牌,在每个请求中会有所不同)(如果某个其他用户获得令牌,那么您有更严重的问题,如会话劫持)。 Notice that this method prevents the user opening on multiple tabs / different browsers as only the last token will be saved. 请注意,此方法会阻止用户在多个选项卡/不同浏览器上打开,因为只保存最后一个标记。 In order to avoid that you have this fantastic answer on SO 为了避免你在SO上这个梦幻般的答案

On the other hand, the second approach allows (logged) users to request directly your myscript.php , but maybe you don't need to prevent that (if you need, just use the first method). 另一方面,第二种方法允许(记录)用户直接请求你的myscript.php ,但也许你不需要阻止它(如果你需要,只需使用第一种方法)。 Notice here you won't have the issue of multiple tabs / different browsers as you'll only check if the user is logged in. 请注意,您不会遇到多个标签/不同浏览器的问题,因为您只会检查用户是否已登录。

how to prevent a user from just going to example.com/myscript.php to execute the script 如何防止用户只是去example.com/myscript.php来执行脚本

From a security perspective, the AJAX call is the same as the user going to that URL. 从安全角度来看,AJAX调用转到该URL的用户相同 That is, the human user and the script you use to make the AJAX call are part of the same security principal. 也就是说,用于进行AJAX调用的人类用户和脚本是同一安全主体的一部分。 If you don't trust the user with access to the PHP script, you can't trust the JavaScript running on the user-controlled computer either. 如果您不信任有权访问PHP脚本的用户,则您也不能信任在用户控制的计算机上运行的JavaScript。

So in what cases can there be separate security principals? 那么在什么情况下可以有单独的安全主体? You could, for example, only deploy the client JavaScript on some kind of tamper-proof kiosk. 例如,您可以仅在某种防篡改信息亭上部署客户端JavaScript。 That way, you could store a secret value in the kiosk, shared with the server. 这样,您可以在服务器中存储一个秘密值,与服务器共享。 The kiosk would send the secret value with each request for the server to validate. 信息亭将发送秘密值,每次请求服务器进行验证。

But if you're doing this for a usability reason, to prevent accidental invocation of the script, then yeah, maybe try that one thing Dirk Pitt linked to. 但是如果你出于可用性的原因这样做,为了防止意外调用脚本,那么,也许尝试Dirk Pitt所关联的一件事。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM