防止查询字符串被篡改

Prevent query string tampering

我写了一个脚本,我需要将 url 中的用户信息作为查询字符串传递到下一页,但是如果我更改传递的参数,与该页面相关的实际数据也会发生变化,因此如何防止alteration/tampering 的查询字符串。我通常不使用查询字符串,所以我真的不知道防止它们被篡改的最佳方法。

用法#1:

<button class="btn btn-blue btn-xs">
    <i class="fa fa-comments"></i>
    <a href="comment.php?u_id='.$row['id'].'&v_no='.$row['vault_no'].'"> Comment</a>
</button>

用法#2:

<form id="form" name="form" method="GET" class="m-t" role="form" action="profile_1.php" autocomplete="off">
    <!--Field parameters-->
    <input style="vertical-align: middle" type="submit" name = "receive" id="submit" value="Post"  class="button">

我将如何处理查询:

if (isset($_GET['Receive'])) {      
    //receiving get parameters
    $xyz = $_GET['xyz'];
    $abc = $_GET['abc'];

您好 您可以使用第一种方法。以下是您的解决方案

1.如果不使用 php 标签

<a href="comment.php?u_id=<?php echo $row['id']; ?>&v_no=<?php echo $row['vault_no']; ?>">Click Here</a>

2。如果使用 with in Php 标签

<?php 
echo "<a href='comment.php?u_id=".$row['id']."&v_no=".$row['vault_no']."'>Check Here2</a>"
?>

您无法阻止用户进行篡改,无论是通过 $_GET 查询篡改还是通过基于 cURL 的查询,这就是它的方式,但您可以让用户更难通过使用加密或令牌进行篡改。假设如果您有任何类型的用户输入,它可能会被篡改。 请注意,无论怎么想,我都不是密码学专家,所以请不要以此为正典。您应该根据需要做更多的研究。 如果您需要保留登录用户的数据,您可能应该考虑使用会话而不是通过 $_GET 查询传递。

双向数据加密:

根据您的需要,openssl 之类的内容可能是一种选择。如果我想传输数据但不一定希望最终用户以明文形式查看,我会使用这种类型的东西。我永远不会在客户端传输敏感数据,但是如果你想阻止你的用户乱搞,这个函数库可能会有一些用处。

openssl_encrypt() 的正确实施将为您提供类似于以下内容的字符串:

nGaotAznsYN69aU%2BNun90vguvhQzk8KW%2BI2RZoom28YqKr05HTeSwPYbMgnPlepj

所以在查询字符串中它看起来像:

<a href="http://www.example.com/?val=nGaotAznsYN69aU%2BNun90vguvhQzk8KW%2BI2RZoom28YqKr05HTeSwPYbMgnPlepj">CLICK</a>

使用此方法,如果解密失败 openssl_decrypt()(因为篡改破坏了字符串)解码应该 return empty,所以您只需考虑 empty :

// $dec would be the decrypted data from $_GET['val']
if(empty($dec))
    die('Invalid data.');

NONCE/TOKEN(S):

如果这是您想要保护的操作(您想确保只有特定用户或组可以 运行 在您的应用程序中执行操作),您可以尝试存储并检查 nonce. WordPress 是一个使用 nonce 相当频繁的应用程序。

如果您要保留的是数据本身,您可能希望使用一对 随机生成的 令牌进行两点身份验证,将一对令牌保存到实际值存储在同一行中的数据库,因此在进行查询时,您可以匹配这两个标记和 return 实际数据(或允许您的程序做出相应反应的动作词):

<a href="http://www.example.com/?key=213Adfa316&token=9821745uwnwoi62626novVBei1qu4p">CLICK</a>

<!--
// the key and token would be in the database along with the corresponding data or action to take,
// you would have to figure that out...
// Then you would just use a select statement to get the data back:
// OF COURSE YOU WOULD BIND VALUES HERE!!!
-->

$smt = "SELECT `savedData` FROM `action_table` where `rKey`='213Adfa316' AND `rToken`='9821745uwnwoi62626novVBei1qu4p'"

注意:有很多不同的方法可以做同样的事情,但如果您使用的是框架,则可能有一种方法是该框架的本机方法.我会对其他方法做更多的研究,但希望这能给你一些想法。正如 @zaph 所指出的,正确实施加密很重要。 @zaph 还指出,如果安全是目标,使用 https 将是保护 client/server 通信的方式。另外要记住的一点是,浏览器可以将查询字符串存储为 url 历史记录的一部分,或者将服务器存储为日志的一部分,因此如果您需要一次性使用 URL,则需要适应重复使用政策。

对此的简短回答是,如果信息真的很敏感,不要将它发送给任何人。保留在本地。您可以改为发送对此信息的引用,将其用作令牌以在以后的请求中检索它。

例如,生成一个 UUID,将包含您的敏感信息的文档保存在某个本地数据存储中,并 link URL 中的 UUID。从 UUID 中收集到的有用信息并不多,至少 none 与秘密存储中的内容有关。

Redis 这样的短期数据存储对于这种持久性很方便。您可以为您的数据设置一个 TTL,以便在将来的某个时候自动清除它。 24-48小时的过期时间应该足够了,如果每次使用都需要延长这个过期时间是可以的。

真正随机的 UUID 是无法猜测的。如果这是一个问题,任何试图暴力破解的人都应该被服务器上的速率限制机制捕获。