PHP URL 安全问题
我想让用户将 url 存储在我的数据库中我正在使用 php mysql 和 htmlpurifier 我想知道以下代码是否是在将坏数据存储到数据库之前过滤掉坏数据的好方法?
这是部分 PHP 代码。
$url = mysqli_real_escape_string($mysqli, $purifier->purify(htmlspecialchars(strip_tags($_POST['url'])));
I want to have users store the url in my database I'm using php mysql and htmlpurifier I was wondering if the following code was a good way to filter out bad data before I store it in the database?
Here is the Partial PHP code.
$url = mysqli_real_escape_string($mysqli, $purifier->purify(htmlspecialchars(strip_tags($_POST['url'])));
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您不需要对数据调用
htmlspecialchars()
和HTMLPurifier
- 这里实际上只有一个问题,那就是确保 URL 不包含SQL 注入 -mysqli_real_escape_string()
会对它进行排序。或者,如果您将数据输出到页面/HTML(而不是将其用作 HTTP 重定向标头),则需要使用
htmlentities()
来防止数据在输出时出现 XSS它。黄金法则是上下文感知:有关 XSS 预防的深入参考,请查看 OWASP。
最好在使用数据之前对其进行编码(针对相关攻击)(即,将 MySQL 转义字符串输入数据库以防止 SQLi,将 HTML 转义字符串输出到屏幕以防止 XSS,但不要同时进行这两种操作)。这使您可以跟踪应用程序中的数据流,并且您知道数据库中的所有数据已准备好用于任何目的。例如,如果您在将这些数据放入数据库之前对其进行 HTML 编码,则必须在将其用作 HTTP 标头之前对其进行取消编码。
如果您必须在数据进入数据库之前对数据进行编码,请确保列名称反映了这一点,以供未来的开发人员/维护人员参考!
编辑:
根据 VolkerK 的评论,防止 URL 输出中出现 XSS 的最佳方法是检查协议 - 如果它与您允许的协议(可能是 http/https)不匹配,则拒绝它:
这有在
情况下防止
javascript:alert('xss')
攻击的优势。在javascript:alert('xss')
上运行htmlentities()
没有任何影响(因为字符的有限子集,例如<>
不存在可被转义),因此恶意用户将能够在您的域上执行 JS。You don't need to call
htmlspecialchars()
and theHTMLPurifier
on the data - you've really only got one issue here and that's making sure the URL doesn't contain a SQL injection -mysqli_real_escape_string()
will sort that.Alternatively, if you're outputting the data to a page/HTML (instead of using it as HTTP redirect headers) you'll need to use
htmlentities()
to protect against XSS on the data WHEN YOU OUTPUT IT. The golden rule is context awareness:For an in-depth reference to XSS prevention, check out OWASP.
It's always best to encode the data (against the relevant attack) just before it's used (i.e. MySQL escape strings for input into database to prevent SQLi, HTML escape strings for output to screen to prevent XSS, not both at the same time). This allows you to keep track of the flow of data through your application, and you know that all data in the database is ready for any purpose. If you HTML encode this data before putting it into the DB, you'll have to un-encode it before using it as a HTTP header, for example.
If you must encode the data before it goes into the database, make sure the column name reflects this for future developers/maintainers!
EDIT:
As per VolkerK's comment, the best way to prevent XSS in URL output would be to check the protocol - if it doesn't match your allowed protocols (probably http/https) reject it:
This has the advantage of preventing
javascript:alert('xss')
attacks in<a href="$url">
situations. Runninghtmlentities()
onjavascript:alert('xss')
has no affect (as the limited subset of characters such as<>
are not present to be escaped), so a malicious user would be able to execute JS on your domain.在将值放入数据库之前,只需要
mysqli_real_escape_string()
。为了防止 XSS,应该在显示的所有数据(在 HTML 中)时调用
htmlspecialchars()
,而不是在存储之前。想象一下,有一天您可能需要以 HTML 以外的格式输出数据;那么你会后悔在将所有内容存储到数据库之前调用
htmlspecialchars()
。我不知道你为什么要使用
purifier
和strip_tags()
,也许你有一个特定的原因,但它看起来像是“越多层”的过度杀伤力我使用的数据清理方法越好”。htmlspecialchars()
无论如何都会使任何 HTML 无害。Only
mysqli_real_escape_string()
is necessary before you put the value in the database.To secure against XSS,
htmlspecialchars()
should be called on all data you display when it is displayed (in HTML), not before it is stored.Imagine that you might one day need to output the data in a format other than HTML; then you will regret having called
htmlspecialchars()
on everything before it was stored in your database.I don't know why you're using
purifier
andstrip_tags()
, perhaps you have a particular reason but it just looks like overkill along the lines of "the more layers of data cleaning I use, the better".htmlspecialchars()
will make any HTML harmless anyway.如果您担心 SQL 注入,这将清理它并防止这种情况发生。否则,不确定你到底在问什么。
If you're worried about SQL Injection, this will clean it up and prevent that. Otherwise, not sure exactly what you're asking.
如果您只需要将 URL 存储在数据库中并取回它们,只需将字符串传递给
mysqli_real_escape_string
一次就足够了。不需要任何其他东西。仅当您想在 HTML 页面中将其输出回用户时,才需要使用 htmlspecialchars。HTMLPurifier 根本不属于这里,因为它清理 HTML,而不是 URL。
If you only need to store the URLs in the database and get them back, just passing the string through
mysqli_real_escape_string
once will suffice. No need for anything else. You will only need to use htmlspecialchars when you want to output it back to a user in a HTML page.HTMLPurifier does not belong here at all, since it cleans HTML, not URLs.
我将 url 存储在我的数据库中,它仅被 xss 清理,但会被 orm 自动转义。这本质上可以归结为:
所以你首先清理它,然后确保可以保存在数据库中,然后保存未更改的 url。
然而,在它的出路中,您可以将其拉出,然后在模板中使用 htmlentities() ,以防万一其中有任何内容可能会干扰 html。
你真的不需要过度设计这样的东西。
附言。如果您正在使用 POST,您可以这样做:
然后使用 $fixed 数组。
I store urls in my db and it is only xss cleaned, but automatically escaped by an orm. This essentially boils down to:
So you clean it first, then make sure it's ok to save in the db, then save the unaltered url.
On it's way out however you would pull it and then in your template use htmlentities() just in case there was anything in it that may interfere with html.
You don't really need to over engineer something like this.
PS. if you're working with POST you could do:
Then work with the $fixed array.
您需要区分过滤和转义。当收到数据时,应该对其进行过滤。这意味着剔除不良字符和有缺陷的数据。
使用过滤器扩展和适当的过滤器将数据从超全局数组传输到应用程序变量。
之后,您可能需要清空 $_POST 以避免再次使用未过滤的数据。
然后你将其按摩成你想要的形状。
转义是数据发送或保存之前的步骤,应根据输出介质进行转义。
使用 mysqli_real_escape_string 转义以存储在 MySQL DB 中。如果您使用另一个 DBMS,则应该使用另一个函数。
更好的是,对用户数据使用准备好的语句和占位符。
当输出为 HTML 时,htmlentities 可能是明智的。前提是您根本不想在数据中包含任何 HTML 代码。如果这样做,请使用受信任的库,例如 HTMLPurifier。
我建议您不要尝试在一行代码中完成所有操作,如您的示例所示。这更难阅读,也更难维护。
对于 URL,htmlentities 是避免未转义的好方法。人物。他们当然应该是&它还确保您没有使用任何引号,因为您当然也使用该标志来引用那些引号 - 对吗?
但在存储数据时不应该应用此功能。它应该在发送给用户时应用。
过滤输入-转义输出! (引用克里斯·希夫莱特的话)
You need to differentiate between filtering and escaping. When data is received one should have it filtered. That means stripping out bad characters and flawed data.
Transfer your data from the superglobal arrays to application variables, using the filter extension, and appropriate filters.
After that point you might want to empty $_POST to avoid using the unfiltered data again.
Then you'll massage it into the shape you want.
Escaping is the step just before data is being sent or saved, and should be done according to the output medium.
Escape with mysqli_real_escape_string for storing in a MySQL DB. If you use another DBMS, you should use another function.
Better yet, use prepared statements and placeholders for user data.
When outputting as HTML, htmlentities might be wise. Provided you do not want to have any HTML code at all in the data. If you do, use a trusted library like HTMLPurifier.
I recommend that you do not try to do everything in one line of code, as in your example. That is harder to read and harder to maintain.
For URLs, htmlentities is a good way to avoid unescaped & characters. They should of course be & It also makes sure you are not using any quotation marks, since you of course use the flag to have those quoted as well - right?
But this function should not be applied when storing the data. It should be applied when it is being sent to the user.
Filter input - escape output! (Quoting Chris Schifflett)