这样危险的标记过滤掉。最好是在提交得时候就进行过滤,这需要一点正则表达式的知识。
The Cross Site Scripting FAQ at cgisecurity.com provides much more information and background on this type of flaw, and explains it well. I highly recommend reading and understanding it. XSS flaws can be difficult to spot and are one of the easier mistakes to make when programming a PHP application, as illustrated by the high number of XSS advisories issued on the popular security mailing lists.
SQL注入的危险
SQL injection vulnerabilities are yet another class of input validation flaws. Specifically, they allow for the exploitation of a database query. For example, in your PHP script, you might ask the user for a user ID and password, then check for the user by passing the database a query and checking the result.
SQL注入攻击是另一种输入验证上的漏洞。这种漏洞可以允许执行数据库命令。例如,在你的PHP脚本中,可能会要求用户输入用户ID和密码,然后通过数据库查询获得结果来检查用户ID和密码是否正确。
SELECT * FROM users WHERE name='$username' AND pass='$password';
However, if the user who's logging in is devious, he may enter the following as his password:
但是,如果一个用户在登录时不怀好意,他可能会这样输入密码:
' OR '1'='1
This results in the query being sent to the database as:
执行数据库的命令就成为如下所示:
SELECT * FROM users WHERE name='known_user' AND pass='' OR '1'='1';
This will return the username without validating the password -- the malicious user has gained entry to your application as a user of his choice. To alleviate this problem, you need to escape dangerous characters from the user-submitted values, most particularly the single quotes ('). The simplest way to do this is to use PHP's addslashes() function.
这样就会不经过密码验证而返回用户名——恶意用户就会任意选择用户名登录。为了避免这样的问题,应该对用户提交的数据进行危险字符的过滤,最主要的就是单引号(’)的过滤。一个简单的方法就是用addslashes函数过滤。
$username = addslashes($_POST["username"]);
$password = addslashes($_POST["password"]);
But depending on your PHP configuration, this may not be necessary! PHP's much-reviled magic quotes feature is enabled by default in current versions of PHP. This feature, which can be disabled by setting the magic_quotes_gpc php.ini variable to Off, will automatically apply addslashes to all values submitted via GET, POST or cookies. This feature safeguards against inexperienced developers who might otherwise leave security holes like the one described above, but it has an unfortunate impact on performance when input values do not need to be escaped for use in database queries. Thus, most experienced developers elect to switch this feature off.
但是根据你的PHP设置,也许可以不需要这样做。PHP一个经常被争论的问题就是magic quotes在当前版本中默认设置为启用。这个特性——可以在php.ini文件中设置magic_quotes_gpc变量来禁用——会自动的对 GET,POST和cookie变量进行addslashes过滤。这个特性是针对缺乏经验的开发者有可能留下上文所述的安全漏洞,但是在不需要过滤的情况下,会对性能产生一些负面影响。所以,大多数有经验的开发者都会关掉这个特性。
If you're developing software that may be installed on shared servers where you might not be able to change the php.ini file, use code to check that status of magic_quotes_gpc and, if it is turned on, pass all input values through PHP's stripslashes() function. You can then apply addslashes() to any values destined for use in database queries as you would normally.
如果你是在共享主机上开发软件,可能会没有权限修改php.ini,那么用函数检查magic_quotes_gpc选项的设置,如果是启用,则将所有输入得数据用stripslashes函数过滤掉转义,然后再像往常一样对需要的数据进行addslashes过滤。
if (get_magic_quotes_gpc()){
$_GET = array_map('stripslashes', $_GET);
$_POST = array_map('stripslashes', $_POST);
$_COOKIE = array_map('stripslashes', $_COOKIE);
}
SQL injection flaws do not always lead to privilege escalation. For instance, they can allow a malicious user to output selected database records if the result of the query is printed to your HTML output.
通常SQL注入不会导致用户权限上的问题,只会允许恶意用户获得某些特定数据库和数据表中的内容。
You should always check user-provided data that will be used in a query for the characters '",;() and, possibly, for the keywords "FROM", "LIKE", and "WHERE" in a case-insensitive fashion. These are the characters and keywords that are useful in a SQL insertion attack, so if you strip them from user inputs in which they're unnecessary, you'll have much less to worry about from this type of flaw.
你应当检查用户提交的所有数据,其中可能包含数据库命令用到的字符例如单引号,双引号,逗号,分号和括号。如果可能,对“FROM”,“LIKE”和 “WHERE”这样的关键词进行不区分大小写的检查。这些都是SQL注入攻击中常用的字符和关键词,如果你不需要用到他们则将他们过滤调,这样此类攻击的危险就会大大降低。
Error Reporting
错误报告
You should ensure that your display_errors php.ini value is set to "0". Otherwise, any errors that are encountered in your code, such as database connection errors, will be output to the end user's browser. A malicious user could leverage this flaw to gain information about the internal workings of your application, simply by providing bad input and reading the error messages that result.
你应当确保php.ini中display_errors重的设置为0,否则,你的代码产生的任何错误,例如数据库连接错误,将会显示在最终用户面前。一个恶意用户只要输入一些非法数据然后观察、分析错误信息,就会获得程序内部运行机制的一些信息。
The display_errors value can be set at runtime using the ini_set function, but this is not as desirable as setting it in the ini file, since a fatal compilation error of your script will still be displayed: if the script has a fatal error and cannot run, the ini_set function is not run.
Display_errors的值可以在运行期间通过ini_set函数来设置,但仍然不如通过在php.ini中设置。如果你的脚本发生了一个致命错误而终止了运行,那么ini_set函数就不会起作用,错误信息仍然会被显示。
Instead of displaying errors, set the error_log ini variable to "1" and check your PHP error log frequently for caught errors. Alternatively, you can develop your own error handling functions that are automatically invoked when PHP encounters an error, and can email you or execute other PHP code of your choice. This is a wise precaution to take, as you will be notified of an error and have it fixed possibly before malicious users even know the problem exists. Read the PHP manual pages on error handling and learn about the set_error_handler() function.
为了替代直接显示错误信息,把ini中的error_log设为1,并且经常检查PHP的错误日志来获取错误信息。通常,你也可以写一个自己的错误处理函数来处理PHP中产生的错误,并可以用email通知你或者执行特定的一段PHP代码。在恶意用户知道一个可能的错误产生之前就将错误修复,这是一个明智的事先准备工作,。可以去PHP手册中的错误处理部分看一下set_error_handler函数的用法。
Data Handling Errors
数据处理错误
Data handling errors aren't specific to PHP per se, but PHP application developers still need to be aware of them. This class of error arises when data is handled in an insecure manner, which makes it available to possible interception or modification by malicious parties.
数据处理错误并非只针对PHP,但PHP的开发人员仍然需要注意。此类错误通常是因为采用了不安全数据处理方法,而且会导致恶意用户对数据的监听或者修改。
The most common type of data handling error is in the unencrypted HTTP transmission of sensitive data that should be transmitted via HTTPS. Credit card numbers and customer information are the most common types of secured data, but if you transmit usernames and passwords over a regular HTTP connection, and those usernames and passwords allow access to sensitive material, you might as well transmit the sensitive material itself over an unencrypted connection. Use SSL security whenever you transmit sensitive data from your application to a user's browser. Otherwise, a malicious eavesdropper on any router between your server and the end user can very easily sniff the sensitive information out of the network packets.
最常见的数据处理错误就是将本来应该通过HTTPS传送的数据在未加密的HTTP上传输。信用卡密码和用户个人信息应该是作为私密的安全信息来处理,但是如果你通过普通的HTTP连接来传输用户名和密码,那么你也很可能用这种未加密的方式来传输那些敏感的数据。在你的应用程序和用户的浏览器通讯时,一定用 SSL安全连接来传输敏感的信息。否则,恶意的监听者就可以在你的应用程序与最终用户之间的任何路由器上通过数据包探嗅到那些敏感的信息。
The same type of risk can occur when applications are updated using FTP, which is an insecure protocol. Transferring a PHP file that contains database passwords to your remote Webserver over an insecure protocol like FTP can allow an eavesdropper to sniff the packets and reveal your password. Always use a secure protocol like SFTP or SCP to transmit sensitive files. Never allow sensitive information to be sent by your application via email, either. An email message is readable by anyone who's capable of reading the network traffic. A good rule of thumb is that if you wouldn't write the information on the back of a postcard and put it through the mail, you shouldn't send it via email, either. The chance anyone will actually intercept the message may be low, but why risk it?
在使用FTP这种不安全的协议时会承担同样的风险。用FTP上传包含数据库用户名和密码的PHP文件到远程WEB服务器时,恶意的监听者就会通过探嗅数据包来获得密码。一定要用SFTP或者SCP协议来传输敏感的文件,也不要用email来传输敏感信息。对于任何有能力获得网络传输数据的人来说,email的信息都是可读的。就像你不会把重要信息写在明信片的背面然后投到信箱里一样,你也不要用email来传递这些信息。虽然实际上这些信息被监听的机会很小,但是为什么要承担这个风险?
It's important to minimize your exposure to data handling flaws. For example, if your application is an online store, is it necessary to save the credit card numbers attached to orders that are more than six months old? Archive the data and store it offline, limiting the amount of data that can be compromised if your Webserver is breached. It's basic security practice not only to attempt to prevent an intrusion or compromise, but also to mitigate the negative effects of a successful compromise. No security system is ever perfect, so don't assume that yours is. Take steps to minimize the fallout if you do suffer a penetration.
重要的一点就是尽可能的减少暴露数据处理错误的漏洞。例如,如果你的应用程序是一个在线商店,对那些6个月之前的信用卡号和订单还有必要保存么?将他们放在一个离线的机器上作为存档,并对这些数据的数量做一个限制防止万一这些机器被非法入侵。对于阻止入侵和减少安全威胁,或者是尽可能的减少一次成功黑客的攻击所带来的损失,这些都是最基本的原则。没有一个安全系统是完美的,所以不要存有侥幸心理。如果你存在入侵的风险一定要采取措施来减少损失。
Configuring PHP For Security
配置PHP的安全选项
Generally, most new PHP installations that use recent PHP releases are configured with much stronger security defaults than was standard in past PHP releases. However, your application may be installed on a legacy server that has had its version of PHP upgraded, but not the php.ini file. In this case, the default settings may not be as secure as the default settings on a fresh install.
通常来讲,通过最新发布的PHP来进行安装,比起之前发布的PHP,都会获得更见安全的配置选项。你的应用程序也许会放在一个通过升级来获得最新PHP版本的web服务器上,但是php.ini没有升级。在这种情况下,默认设置也许就不会像新的安装一样安全。
You should create a page that calls the phpinfo() function to list your php.ini variables and scan them for insecure settings. Keep this page in a restricted place and do not allow public access to it. The output of phpinfo() contains information that a potential hacker might find extremely useful.
你应当创建一个包含phpinfo()函数的页面,列出你的php.ini变量来检查不安全的设置。把这个页面保存在特定的地方,不要让公共人员可以访问。Phpinfo()产生的信息会包含那些对黑客十分有用的信息。
Some settings to consider when configuring PHP for security include:
配置PHP安全选项时下面是要考虑到的:
1. register_globals: The boogeyman of PHP security is register_globals, which used to default to "on" in older releases of PHP but has since been changed to default to "off". It exports all user input as global variables. Check this setting and disable it -- no buts, no exceptions. Just do it! This setting is possibly responsible for more PHP security flaws than any other single cause. If you're on a shared host, and they won't let you disable register_globals, get a new host!
2. safe_mode: The safe mode setting can be very useful to prevent unauthorized access to local system files. It works by only allowing the reading of files that are owned by the user account that owns the executing PHP script. If your application opens local files often, consider enabling this setting.
3. disable_functions: This setting can only be set in your php.ini file, not at runtime. It can be set to a list of functions that you would like disabled in your PHP installation. It can help prevent the possible execution of harmful PHP code. Some functions that are useful to disable if you do not use them are system and exec, which allow the execution of external programs.
1. Register_globalsHP 安全的最大杀手就是register_globals。在PHP过去的版本中这个设置默认是为on的,但是在最近的版本中关掉了此项设置。这个选项可以把用户所有的输入作为全局变量,你所要做的就是检查这这项设置并且关掉它——没有但是,也没有例外,一定要这样做!这项设置是其他PHP安全漏洞最大的潜在隐患,如果你在使用共享主机但是却不能禁止register_globals,那么就换一个空间服务商!
2. Safe_mode:阻止未授权的用户访问本地文件系统,这个选项是十分有用的。它只允许拥有此脚本的用户来执行读文件的操作。如果你的应用程序经常打开本地文件,记住要启用此项设置。
3. Disable_functions:这项设置不能在运行期间修改,只能在php.ini文件中设置。你可以在此项设置中创建一个函数列表来禁用这些函数。这样就能阻止潜在的危险的PHP代码的执行。system和exec函数如果你用不到的话,就将他们禁用,因为这些函数允许执行内部其他程序。
Read the security section of the PHP manual and get to know it well. Treat it as material for a test you'll take and get to know it backwards and forwards. You will be tested on the material by the hackers who will indubitably attempt to penetrate your site. You get a passing grade on the test if the hackers give up and move on to an easier target whose grasp of these concepts is insufficient.
去读一下PHP手册中的安全部分,那么你就可以更好的了解这些。把这当作一次测试,你就可以更好的了解来龙去脉。一些黑客在尝试入侵你的站点时你的安全知识就会得到检验。如果那些黑客放弃了攻击或者转向其他更容易攻击的对象,那么你就通过了考试。
Further Reading
The following sites are recommended reading to maintain your security knowledge. New flaws and new forms of exploits are discovered all the time, so you cannot afford to rest on your laurels and assume you have all the bases covered. As I stated in the introduction to this article, "Security is a process", but security education is also a process, and your knowledge must be maintained.
推荐你去下面的站点看一下来获取更多的安全知识。新的漏洞和入侵一直都在被发现,所以对于以往的成功安全措施没有任何值得骄傲的地方,一定要有未雨绸缪的心态。正如我在文章开始所说,“安全措施是一个过程”,同样学习安全知识也是一个过程,你必须要牢牢掌握这些知识。
OWASP, The Open Web Application Security Project, is a non-profit oganisation dedicated to "finding and fighting the causes of insecure software". The resources it provides are invaluable and the group has many local chapters that hold regular meetings with seminars and roundtable discussions. Highly recommended.
OWASP, The Open Web Application Security Project,一个致力于软件不安全因素收集和研究的非盈利性组织。他们所提供的资源是无法估量的,并且他们定期举行研讨会和一些非正式的讨论。强烈推荐。
CGISecurity.Net is another good site dealing with Web application security. They have some interesting FAQs and more in-depth documentation on some of the types of flaws I've discussed in this article.
CGISecurity.Net是另一个关注web应用安全的站点。他们有一些很有趣的常见问题集锦,对我在上文提到得一些安全问题也有更深的讨论。
The security section of the PHP Manual is a key resource that I mentioned above, but I include it here again, since it's full of great information that's directly applicable to PHP. Don't gloss over the comments at the bottom of each page: some of the best and most up-to-date information can be found in the user-contributed notes.
The security section of the PHP Manual有很多与PHP直接相关的非常有用的信息,我在上文已经提到过,但还要在这里强调一次。不要忽视每一页下面的用户评论,一些相当不错的最新信息都会在这里找到。
The PHP Security Consortium offers a library with links to other helpful resources, PHP-specific summaries of the SecurityFocus newsletters, the PHP Security Guide, and a couple of articles.
The PHP Security Consortium提供一个连接到其他资源的库,针对PHP的安全新闻通讯,PHP安全向导和一些文章。
The BugTraq mailing list is a great source of security related advisories that you should read if you're interested in security in general. You may be shocked by the number of advisories that involve popular PHP applications allowing SQL insertion, Cross Site Scripting and some of the other flaws I've discussed here.
The BugTraq mailing list是一个很大的安全资讯站点,如果你对安全方面感兴趣,一定要看一下。这里有很多关于PHP的SQL注入,跨站脚本攻击的安全建议,并且数量惊人。
Linux Security is another good site that is not necessarily restricted to PHP but, since you are likely running a Linux Webserver to host your PHP applications, it's useful to try to stay up to date on the latest advisories and news related to your chosen Linux distribution. Don't assume your hosting company is on top of these developments; be aware on your own -- your security is only as good as your weakest point. It does you no good to have a tightly secured PHP application running on a server with an outdated service that exposes a well-known and exploitable flaw.
Linux Security是一个不错的站点,虽然并非只针对PHP,但是如果你在一台Linux服务器上运行PHP,在这里多读一些关于你所用Linux版本的安全资讯还是很有用的。不要以为你的空间服务商总是把安全措施做的很好,你自己就要注意——像对待你的缺点一样改正它们。在一个存有常见安全漏洞并且没有及时更新的服务器上运行对安全要求很高的PHP脚本,是没有一点好处的。
Conclusions
总结
As I've shown in this article, there are many things to be aware of when programming secure PHP applications, though this is true with any language, and any server platform. PHP is no less secure than many other common development languages. The most important thing is to develop a proper security mindset and to know your tools well. I hope you enjoyed this article and learned something as well! Remember: just because you're paranoid doesn't mean there's no one out to get you.
正如本文所述,像其他语言和平台一样,PHP编程需要注意很多安全方面的问题。PHP和其他许多编程语言一样,本身是十分安全的。最重要的就是有一个正确的安全理念,并且对PHP要相当熟悉。我希望你能喜欢这篇文章并且能从中获益。记住:对于安全问题,不要存在任何侥幸心理!