【问题标题】:Security and Deprecated Filters安全和不推荐使用的过滤器
【发布时间】:2019-12-06 11:35:30
【问题描述】:

在我的网站上,用户可以提交包含他们的姓名、电子邮件和金额的表单。

<input type='text'  minlength='2' maxlength='30' spellcheck='false' placeholder='Elon'           autocomplete='off' form='form' required>
<input type='email' minlength='6' maxlength='40' spellcheck='false' placeholder='musk@tesla.com' autocomplete='off' form='form' required>
<input type='number' step='0.01' min='2000' max='99999999.99'       placeholder='$2,000.00'      autocomplete='off' form='form' required>

但是,不是发布 HTML 表单,而是在一个 JS 函数中解析值,然后将包含所有参数的字符串发送到另一个创建 AJAX 请求的函数。

form.onsubmit = function(e){
  const
    children = this.children,
    summary = this.parentNode.parentNode.children[0].innerText.split('.'),
    negotiate = this.parentNode.children[1]
  insert_data(`table=offers
    &name=${children[0].value.toLowerCase()}
    &email=${children[1].value.toLowerCase()}
    &amount=${children[2].value * 100}
    &sld=${summary[0]}
    &tld=${summary[1]}`
  )
  return false
}

function insert_data(parameters, async){
  async = async === undefined || async
  let xhr = window.XMLHttpRequest
    ? new XMLHttpRequest()
    : new ActiveXObject('Microsoft.XMLHTTP')
  xhr.open('POST', 'ajax.php', async)
  xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded;charset=UTF-8')
  xhr.send(parameters)
}

考虑到这一点,这是我的第一个问题:为了安全起见,是否应该对 insert_data(parameter string) 进行编码,即使它已发布并且实际上并未作为实际 URL 中的参数传递?

下面是 AJAX 请求向其发布数据的 PHP。在脚本中,我试图在插入数据之前对其进行清理。

今天早些时候,我在 SO 上读到 htmlspecialchars() 和准备好的语句应该就足够了,而且在清理输入方面没有什么可以做的。但我想我不妨尽我所能。

$name = trim(strtolower(htmlspecialchars($_POST["name"])));
$email = trim(strtolower(filter_var($_POST["email"], FILTER_SANITIZE_EMAIL)));
$amount = trim(filter_var($_POST["amount"], FILTER_SANITIZE_NUMBER_INT));
$sld = trim(strtolower(htmlspecialchars($_POST["sld"])));
$tld = trim(strtolower(htmlspecialchars($_POST["tld"])));

我之前还读到FILTER_SANITIZE_MAGIC_QUOTES 现在已弃用,尽管the documentation. 中根本没有提及这一点因此,我想知道是否也弃用了以下任何过滤器?

  • FILTER_SANITIZE_EMAIL
  • FILTER_SANITIZE_NUMBER_INT
  • FILTER_SANITIZE_SPECIAL_CHARS
  • FILTER_SANITIZE_FULL_SPECIAL_CHARS
  • FILTER_SANITIZE_STRING

我的最后一个问题是,如果上面的过滤器都没有被弃用,我应该为$name$sld$tld 使用最后三个过滤器中的哪一个,它们应该是基本的 ASCII字符串?它们看起来都非常相似......

谢谢

【问题讨论】:

  • 您能否将您读到FILTER_SANITIZE_MAGIC_QUOTES 已弃用的链接提供给我们?刚刚在 PHP 7 中对其进行了测试,它可以工作。
  • @KIKOSoftware 试图找到它。给我一秒钟
  • 那个答案说 magic quotes 已被弃用。 过滤器仍然可用,如果你需要它来处理魔术引号的后果,即使它们已经死了多年。
  • @deceze 是的,我知道它说魔术引号已被弃用。 但文档中没有提及它的弃用,这让我认为其他 FILTERS 也可能被弃用,我们永远不会知道

标签: php mysql ajax database insert


【解决方案1】:
`table=offers&name=${children[0].value.toLowerCase()}...`

这里有问题。如果任何值包含&amp; 和/或=,则此查询字符串的含义将被更改,并且至少您会丢失信息。您需要 encodeURIComponent 每个单独的值,然后再将其放入查询字符串中,例如:

`table=offers&name=${encodeURIComponent(children[0].value.toLowerCase())}...`

您无需对任何内容进行编码即可通过 HTTP 发送。 TL;DR 是,如果您有兴趣向第三方隐藏信息,则必须使用 HTTPS,没有明智的解决方法。

$name = trim(strtolower(htmlspecialchars($_POST["name"])));

只是……不要。不要对您的值进行 HTML 编码用于存储。如果您在纯文本电子邮件中发送此值,或者在其他一些非 HTML 上下文中使用它会怎样?它将包含 HTML 实体。这就是“亲爱的奥康纳先生”之类的事情发生的方式。

只需将普通值按原样存储在数据库中即可。您可能想要验证它们,例如检查一封电子邮件是否看起来像一封电子邮件,但除非您有充分的理由,否则您不应更改这些值。

使用准备好的语句来防止 SQL 注入。如果您曾经在某处再次输出这些值,请在该点正确编码/转义它们;例如htmlspecialchars 将它们输出到 HTML 时。

见:

【讨论】:

  • 啊,不错。一旦它们通过 AJAX 请求发布到 PHP 文件,我将需要对这些值进行解码,对吗?我不打算将它们作为编码值插入。我只是想尽我所能防止 SQL 注入和 XSS。生病阅读这些链接
  • 关于FILTERS的任何想法??我最担心的是有人可以使用他们可以想象的任何参数来调用insert_data(),然后将其发布到PHP文件中。
  • 不,您不需要在 PHP 端对它们进行解码。如果您使用$_POST,它们已经被 PHP 解析和适当解码。如果您在 PHP 中手动解析该查询字符串,您只需要担心这一点,而您不是。通常,在编码/转义方面,越多越好。为正确的上下文正确执行 once 就足够了。用于在 URL 查询字符串中嵌入值的 URL 编码。 HTML 编码为 HTML。 SQL 转义;或者更好地使用prepared statements,并且完全不用担心转义。
  • 是的,任何人都可以随时向您的服务器发出任意 HTTP 请求。对此你无能为力。这就是为什么您在对服务器执行任何操作之前验证接收到的数据。
  • 好酷。我正在使用准备好的语句,但我不应该FILTER 数据以进行安全测量吗?或者我想如果我验证数据,真的不需要FILTERING,对吧?
猜你喜欢
  • 2016-03-20
  • 1970-01-01
  • 2017-07-15
  • 2011-08-18
  • 2021-10-06
  • 2021-12-24
  • 2014-02-15
  • 1970-01-01
  • 2014-02-02
相关资源
最近更新 更多