登录后重定向到上一页的最佳实践是什么?PHP

登录后重定向到上一页的最佳实践是什么?PHP,php,security,redirect,login,code-injection,Php,Security,Redirect,Login,Code Injection,登录后,我想将用户重定向回他们使用PHP时所在的页面。在对这个问题进行了一些搜索,但没有找到任何好的解决方案之后,我决定在登录表单中添加一个隐藏字段,该字段使用$\u SERVER['REQUEST\u URI']包含当前的部分URL。 服务器使用此信息在用户登录后将其重定向回上一页。这是正确的,但我的问题是 总的来说,一旦url返回到服务器,我需要对其应用哪些安全措施,这样,如果被篡改,它就不会将用户重定向到一个外部的、可能严格的站点 例如:如果我将表单中的值从$\u SESSION['REQ

登录后,我想将用户重定向回他们使用PHP时所在的页面。在对这个问题进行了一些搜索,但没有找到任何好的解决方案之后,我决定在登录表单中添加一个隐藏字段,该字段使用$\u SERVER['REQUEST\u URI']包含当前的部分URL。 服务器使用此信息在用户登录后将其重定向回上一页。这是正确的,但我的问题是

总的来说,一旦url返回到服务器,我需要对其应用哪些安全措施,这样,如果被篡改,它就不会将用户重定向到一个外部的、可能严格的站点

例如:如果我将表单中的值从$\u SESSION['REQUEST\u URI']更改为,它将在登录后重定向到Google。最好的消毒方法是什么

*我目前正在使用mysql\u real\u escape\u字符串进行SQL注入

<form action="/signin/" method="post">
<input type="hidden" name="return" value="<?php echo $_SERVER['REQUEST_URI']; ?>" />
</form>
......
$return = mysql_real_escape_string($_POST['return']);
header('Location: '.$return);

我发现了这个,对我来说真的很好:

他在和一个值得信任的推荐人合作

包括这一点,您可以使用多种方法。检查referer、表单中的隐藏字段,如果可以,甚至检查服务器日志


除了服务器日志,我认为没有更好的方法来检查用户来自何处。

我发现了这个,对我来说非常好:

他在和一个值得信任的推荐人合作

包括这一点,您可以使用多种方法。检查referer、表单中的隐藏字段,如果可以,甚至检查服务器日志


除了服务器日志之外,我认为没有更好的方法来检查用户来自何处。

除了登录和登录提交页面之外,您应该将当前url存储在会话变量中,如$\u session[last\u page\u visted]中。因此,每次访问新页面时,$\u会话[上次访问的页面]将被当前url覆盖。因此,无论您访问哪个页面,您访问的最后一个页面的url都会保存在会话中。如果单击“登录”,则在成功登录后从任何页面重定向到该会话中保存的url。如果$会话[上次访问的页面]为空,则重定向到索引页面


希望这能有所帮助。

您应该将当前url存储在会话变量中,如$\u session[last\u page\u visited]中,但登录和登录提交页面除外。因此,每次访问新页面时,$\u会话[上次访问的页面]将被当前url覆盖。因此,无论您访问哪个页面,您访问的最后一个页面的url都会保存在会话中。如果单击“登录”,则在成功登录后从任何页面重定向到该会话中保存的url。如果$会话[上次访问的页面]为空,则重定向到索引页面


希望这能有所帮助。

正如数百条其他答案/评论所指出的那样,现在每个人都应该使用mysqli了。除此之外,mysql\u real\u escape\u string顾名思义是用于转义将在mysql查询中使用的字符串。它没有其他用途。它不能保护您免受XSS攻击,我将演示

设置:

// represent a string without using quotes
function ab($str) {
  $out = array();
  for ($i = 0; $i < strlen($str); $i++) {
    ($chr = _ab($str[$i])) || ($chr = 'String.fromCharCode('.ord($str[$i]).')');
  }
  return implode('+', $out);
}
// represent a character without quotes
function _ab($chr) { 
  $alpha = array(
    'Array', 'Boolean', 'Date', 'Function', 'Iterator', 'Number', 'Object',
    'RegExp', 'String', 'ArrayBuffer', 'Float32Array', 'Float64Array', 'JSON',
    'Int16Array', 'Int32Array', 'Int8Array', 'Uint16Array', 'Uint32Array',
    'Uint8Array', 'Uint8ClampedArray', 'Error', 'EvalError', 'InternalError',
    'RangeError', 'ReferenceError', 'StopIteration', 'SyntaxError', 'parseInt',
    'TypeError', 'URIError', 'decodeURI', 'decodeURIComponent', 'encodeURI',
    'encodeURIComponent', 'eval', 'isFinite', 'isNaN', 'parseFloat', 'uneval'
  );
  // sort function names by length to minimize output
  usort($alpha, function($a, $b){return strlen($a) - strlen($b);});
  foreach ($alpha as $fn) {
    if (($i = strpos($fn, $chr)) !== false) return "$fn.name[$i]";
  }
  return false;
}
$mb = chr(0xC2).chr(0x8F); // eats backslashes for breakfast
它直接通过mysql\u real\u escape\u字符串,因为第一个字符实际上是一个部分多字节字符0xC28F,它会在该字符之后立即吃掉该字符。反斜杠mysql\u real\u escape\u字符串插入以转义引号,生成:

<a href="\" onmouseover=THE_PAYLOAD title=XSS">click me</a>
由于MySQL中没有使用百分比编码,MySQL\u real\u escape\u字符串不知道%27是单引号还是%22是双引号;所以它只是忽略了它们。如果用户单击此链接,它将发送一个POST请求,将其密码更改为攻击者选择的密码。它可以被修改,也可以重定向到用户希望访问的页面,这样他们就不知道刚才发生了什么

对当前设置进行此类攻击的唯一障碍是URI是根相关的,因此它们总是以/开头,但正如第一个示例所示,多字节字符串可以用来欺骗浏览器,即使结果标记被破坏,由于大多数浏览器的HTML解析器的方便性,链接仍然可以工作。在阅读了你的问题后,我只用了15分钟就想出了这个例子。毫无疑问,一个意志坚定的攻击者会想出一些确实构成实际威胁的东西


所以为了安全起见,您必须使用专门为HTML和URL设计的方法清理URI。这是一个很好的开始。否则,这里的其他答案提供了一些更安全的选择。

正如数百个其他答案/评论所指出的,现在每个人都应该使用mysqli了。除此之外,mysql\u real\u escape\u string顾名思义是用于转义将在mysql查询中使用的字符串。它没有其他用途。它不能保护您免受XSS攻击,我将演示

设置:

// represent a string without using quotes
function ab($str) {
  $out = array();
  for ($i = 0; $i < strlen($str); $i++) {
    ($chr = _ab($str[$i])) || ($chr = 'String.fromCharCode('.ord($str[$i]).')');
  }
  return implode('+', $out);
}
// represent a character without quotes
function _ab($chr) { 
  $alpha = array(
    'Array', 'Boolean', 'Date', 'Function', 'Iterator', 'Number', 'Object',
    'RegExp', 'String', 'ArrayBuffer', 'Float32Array', 'Float64Array', 'JSON',
    'Int16Array', 'Int32Array', 'Int8Array', 'Uint16Array', 'Uint32Array',
    'Uint8Array', 'Uint8ClampedArray', 'Error', 'EvalError', 'InternalError',
    'RangeError', 'ReferenceError', 'StopIteration', 'SyntaxError', 'parseInt',
    'TypeError', 'URIError', 'decodeURI', 'decodeURIComponent', 'encodeURI',
    'encodeURIComponent', 'eval', 'isFinite', 'isNaN', 'parseFloat', 'uneval'
  );
  // sort function names by length to minimize output
  usort($alpha, function($a, $b){return strlen($a) - strlen($b);});
  foreach ($alpha as $fn) {
    if (($i = strpos($fn, $chr)) !== false) return "$fn.name[$i]";
  }
  return false;
}
$mb = chr(0xC2).chr(0x8F); // eats backslashes for breakfast
因为第一个字符实际上是一个部分多字节字符0xC28F,它吃 紧随其后的e字符插入反斜杠mysql\u real\u escape\u字符串以转义引号,生成:

<a href="\" onmouseover=THE_PAYLOAD title=XSS">click me</a>
由于MySQL中没有使用百分比编码,MySQL\u real\u escape\u字符串不知道%27是单引号还是%22是双引号;所以它只是忽略了它们。如果用户单击此链接,它将发送一个POST请求,将其密码更改为攻击者选择的密码。它可以被修改,也可以重定向到用户希望访问的页面,这样他们就不知道刚才发生了什么

对当前设置进行此类攻击的唯一障碍是URI是根相关的,因此它们总是以/开头,但正如第一个示例所示,多字节字符串可以用来欺骗浏览器,即使结果标记被破坏,由于大多数浏览器的HTML解析器的方便性,链接仍然可以工作。在阅读了你的问题后,我只用了15分钟就想出了这个例子。毫无疑问,一个意志坚定的攻击者会想出一些确实构成实际威胁的东西


所以为了安全起见,您必须使用专门为HTML和URL设计的方法清理URI。这是一个很好的开始。否则,这里的其他答案提供了一些更安全的选择。

如果登录页面使用SSL/TLS加密,并且您从服务器设置了隐藏表单字段的值,该值已根据您的白名单进行验证,那么如果在提交之前对其进行了修改,则用户会知道,因为他们这样做了


SSL/TLS是最佳实践。

如果登录页面使用SSL/TLS加密,并且您从服务器设置了隐藏表单字段的值,该字段已根据您的白名单进行验证,那么如果在提交之前对其进行了修改,则用户会知道,因为他们这样做了


SSL/TLS是最佳实践。

如果只在会话中保存URL,为什么要使用mysql\u real\u escape?$_SERVER['HTTP\u REFERER']怎么样?我不是在会话中保存URL,它是一个隐藏表单字段的值,该字段被传递到signin.php,它应该重定向回用户登录的网站页面。至于$\u服务器['HTTP\u REFERER'],它与我现在面临的安全问题相同。当我第一次尝试使用它时,它也不起作用。如果只在会话中保存URL,为什么要使用mysql\u real\u escape?$_SERVER['HTTP\u REFERER']怎么样?我不是在会话中保存URL,它是一个隐藏表单字段的值,该字段被传递到signin.php,它应该重定向回用户登录的网站页面。至于$\u服务器['HTTP\u REFERER'],它与我现在面临的安全问题相同。当我第一次尝试使用它时,它也不起作用。除了当用户在同一个会话中打开了多个浏览器窗口时,它们会被重定向到最后一页,即使这是来自其他浏览器的最后一页。您可以通过将URI保存到$\u会话['last\u page'][$token]来避免此问题并重定向到/login?token=$token。这将直接将窗口/选项卡绑定到重定向源。您可以使用time或microtime作为令牌,这样您就可以保留10个最新的URI。这一方法有效,除非用户在同一会话中打开了多个浏览器窗口,然后它们被重定向到最后一页,即使这是来自另一个浏览器的最后一页。您可以通过将URI保存到$\u会话来避免此问题['最后一页][$token]和重定向到/login?token=$token。这将直接将窗口/选项卡绑定到重定向源。您可以使用time或microtime作为令牌,这样您就可以保留10个最新的URI。感谢您提供的信息。我肯定会更多地研究XSS,但是仅此应用程序,使用会话变量来保存是否更简单p跟踪url,不必担心url转义?感谢您提供的信息。我肯定会进一步研究XSS,但是仅此应用程序,使用会话变量跟踪url,不必担心url转义,不是更简单吗?
<a title="XSS"" onmouseover="THE_PAYLOAD" href="\">click me</a>
javascript:$.post(%27/account/change-password%27,{newPassword:%27p0wned%27,newPassword2:%27p0wned%27});undefined;