【发布时间】:2020-10-15 09:07:24
【问题描述】:
我有一些我正在使用 cookie、会话和 csrf 令牌创建登录页面的 php 脚本。这些脚本是面向对象的并使用类,但是 CSRF 令牌是我表单中的隐藏输入,它阻止了提交按钮的呈现。几个月来我一直在盯着它摆弄它,但我无法弄清楚错误在哪里或为什么它阻止了按钮的呈现,我有错误报告但没有显示任何错误。我也在使用 spl_autoload_register() 函数来加载我的类,但我不认为这是问题所在。任何帮助将不胜感激
注册.php
<?php require_once 'Core/init.php';
include 'Core/head.php';
if(!Usr){ // Not doing anything.....
echo '<span style="color:white;">You must be logged in to view properties</span>';
}
?>
<h1 style="color:white;">Let Living Be Life</h1>
<h2 style="color:white;">Property Rentals</h2>
<a href="index.php">Home</a><br>
<a href="profile.php">Profile</a><br>
<a href="register.php">Register</a><br>
<a href="login.php">Login</a><br>
<a href="logout.php">Logout</a><br>
<a href="changepassword.php">Change Password</a><br>
<a href="info.php">Info</a><br>
<input type="radio" name="theme-switch"><span style="color:white;">Theme</span>
<form action="" method="post">
<input id="usrname" type="text" name="usrname"
placeholder="Username" autocomplete="off" required="true">
<input id="psw" type="password" name="psw"
placeholder="password" autocomplete="off" required="true">
<input type="checkbox" name="remember" id="remember"> <span style="color:white;">Remember me.</span>
<!-- This is not being rendered either !!!!!!!!!!!!!!!! -->
<input type="hidden" name="csrf_tokenz" value="<?php echo Token::gen_csrf_token(); ?>"><br> <!-- Added '' around the echo, but it is not generating a valid token, button is back though...-->
<!-- Note, Something is blocking the button from rendering ???????????????????? -->
<button id="Submit_btn" type="submit">Submit</button>
</form>
<a href="index.php">Home</a>
<a href="profile.php">Profile</a>
<a href="register.php">Register</a>
<a href="login.php">Login</a>
<a href="logout.php">Logout</a>
<a href="changepassword.php">Change Password</a>
<a href="info.php">Info</a>
<?php
// $_SESSION['user-type'] = guest; << need to set this at top of loggin page. aswell as other checks.
if(Input::inp_exists()){
if(Token::check_token(Input::post_or_get_inp('csrf_tokenz'))){
$validate = new Validate();
$validation = $validate->check_val($_POST, array(
'usrname' => array('required' => true),
'psw' => array('required' => true)
));
if($validation->vali_passed()){
// Log Usr in..
$usr = new Usr();
$remember = (Input::post_or_get_inp('remember') === 'on') ? true : false;
$login = $usr->login_usr(Input::post_or_get_inp('usrname'), Input::post_or_get_inp('psw'), $remember);
if($login){
Redirect::r_to('index.php');
echo 'Success';
}else{
echo '<p>Sorry Login Failed</p>';
}
}else{
foreach($validation->vali_errors() as $error){
echo $error, '<br>';
}
}
}
}
?>
Token.class.php
<?php // Check all Syntax::>>
class Token{
public static function gen_csrf_token(){ // Csrf Token 1.
return Session::sesh_put(Config::get_conf('session/token_name'), bin2hex(random_bytes(28)).openssl_random_pseudo_bytes(7)); // md5(uniqid()) md5(random_bytes(164))<< this is the old version which is deprecated...
}
public static function gen_csrf_token2(){ // Csrf Token 2.
return Session::sesh_put(Config::get_conf('session/token2_name'), bin2hex(random_bytes(28)).openssl_random_pseudo_bytes(7)); // ::>> Brackets maybe wrong way round in here.
}
public static function genchilli_token(){ // Use this to Build a Pepper, Salt is in the Hash Class. Abstract Away..
$Chilli = bin2hex(128).=openssl_random_psuedo_bytes(48).=md5('x12ii21ii12x');
return $Chilli; // <<:: Test me?
}
public static function check_token($token){
// echo 'I have been run line 15 Token Class';
$token_name = Config::get_conf('session/token_name'); // ::>> index=12
// echo 'I have been run line 16 Token Class';
if(Session::sesh_exists($token_name)&& $token === Session::get_sesh($token_name)){
Session::del_sesh($token_name);
return true;
}
return false;
}
}
Token 类依赖于 Session 和 Conig 类来工作。 即功能: Session::sesh_put() & Config::conf_get() 但我在这里找不到任何错误 或者,并且没有显示任何错误。
Session.class.php
<?php
class Session{
public static function get_sesh($name){
// echo 'Debug Only >> Session::Get Ran';
return $_SESSION[$name]; // ::<< these relate to Token Name in Token.class.php
}
public static function sesh_put($name, $value){
// echo 'Debug Only >> Session::put Ran';
return $_SESSION[$name] = $value;
}
public static function sesh_exists($name){
// echo 'Debug Only >> Session::exists Ran';
return (isset($_SESSION[$name])) ? true : false;
}
public static function del_sesh($name){
if(self::sesh_exists($name)){
unset($_SESSION[$name]);
}
}
public static function sesh_flash($name, $string = ''){ // Used for flashing a msg to user.
if(self::sesh_exists($name)){ // Flash eps 13 // Not returning any messages for some reason..
$session = self::get_sesh($name);
self::del_sesh($name); // This deletes the session
return $session;
} else {
self::sesh_put($name, $string);
}
}
}
// After done upload to code review
?>
配置.php
<?php // ::>> This File Has no Errors. Upto eps 8 No errors spotted so far..
class Config{ // ::>> Need to build in here a check for Faulty Paths then Exit script. destroy session, log user out.
public static function get_conf($path = null){
if($path){
$config = $GLOBALS['config'];
$path = explode('/', $path);
foreach($path as $bit){
if(isset($config[$bit])){
$config = $config[$bit];
}
}return $config;
}return false;
}
}
init.php
<?php
session_start();
error_reporting(E_ALL & E_NOTICE);
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
$GLOBALS['config'] = array(
'mysql' => array(
'host' => 'localhost', // ::> 127.0.0.1
'charset' => 'redacted',
'db-usr' => 'redacted',
'db-psw' => 'redacted',
'db' => 'redacted',
'ssh' => 'false', // ::<< I added these last three for later Updates to Determine access via these three methods.
'cli' => 'false', // <<:: Need very strong Authentication If I every choose to use these.
'cgi' => 'false' // ::>> Set-up two factor Authentication at some point.
),
'remember' => array(
'cookie_name' => 'hashish_cookie',
'cookie_expiry' => '784828'
// 'preferences' => array( // <<:: I added this for later functionality.
// 'usr_pref' => 'has_cat',
// 'needs' => 'null'
// ),
),
'session' => array( // Add different Session types in here ie. Guest, Admin, Mod, ExtMod, RootAd, HasCat.
'session_name' => 'usr_session',
'token_name' => 'csrf_tokenz',
'token2_name' => 'csrf_tokenz2',
'hacker_bait' => 'redacted',
'has_cat' => '0'
)
); // Closing Tag for Globals Array
spl_autoload_register(function($class) {
require_once 'Classes/' . $class . '.class.php';
});
require_once 'Functions/sanitize.php';
if(Cookie::cookie_exists(Config::get_conf('remember/cookie_name')) && !Session::sesh_exists(Config::get_conf('session/session_name'))){
echo 'User Asked to Be remembered!';
$hash = Cookie::get_cookie(Config::get_conf('remember/cookie_name'));
$hashCheck = DB::getInstance()->get_dbr('usr_session', array('hash', '=', $hash)); // <<:: Check if this is xx >> usr_session << Correct one < or usrs_session..
if($hashCheck->count_dbr()){
echo 'Hash matches, log usr in';
} // Unsure if this is dbr_count or count_dbr or a built in pdo version of count?
}
?>
任何帮助或指示将不胜感激,因为我找不到错误及其困扰我。当我重新登录到我的托管站点后,将在一分钟内更新问题并包含 config.php。我已经尝试使用 md5、uniqid、random_bytes、ssl_random_pseudo_bytes 和多种不同的组合,但无法使其正常工作。我知道关于如何安全地生成 CSRF 令牌还有许多其他问题,但我发现没有一个问题是使用类或面向对象的程序,它们也没有解决我的具体问题。我已经阅读了多个不同的,其中一些有助于我理解但没有解决这个问题。
图像显示正在渲染的内容以及停止或中断的位置。 正如 Mike 在 cmets 中建议的那样使用 Ctrl + U。
更新,在阅读 Mike 分享的帖子后,刚刚在 E_NOTICE 错误报告中添加了一个 ~:Error Reporting,它生成了一个以前没有显示的新通知,因此这可能有助于解决这些问题。图片如下:
修正:注释掉辣椒函数的内部......
【问题讨论】:
-
当你说当你输出 CSRF 令牌时它会阻止提交按钮呈现,这向我表明正在回显一条错误消息并使你的页面具有无效的 HTML,这就是为什么它不是被渲染到屏幕上。除非您在生成页面后使用某种输出缓冲和操作页面,否则没有理由不存在提交按钮。您需要查看实际的输出页面源,而不是浏览器如何决定将其呈现到屏幕上。
-
另外,根据this answer,
bin2hex(random_bytes(32))应该足以生成 CSRF 令牌。我建议坚持使用它,而不是使用不同的随机数生成器来复杂化。 -
@Mike 感谢您的回复我已经在 Firefox 开发者版的 devtools 中检查了源代码,但未包含隐藏输入字段,它应该显示生成的令牌灰色且非可编辑,但它甚至没有显示,所以在 php 的某个地方有一个错误,ps 我没有使用任何缓冲区..
-
你还是找错地方了。开发工具不会向您显示您想要什么,因为这是浏览器解析 HTML 的方式。您需要查看页面的实际源代码。按 Ctrl-U。
-
在评论中的代码之后输出是否突然结束?如果没有,请将其发布在您的问题中。如果确实这样结束,请检查您的日志文件。它很可能会产生某种错误或异常,从而在那时杀死脚本。