我在构建门户网站时遇到问题,因此决定通过小型压力测试进一步调查。该测试为一个指定密码生成了 4,000/10,000/50,000 种不同的盐。代码如下:
$Incline = 0;
$Max = 4000;
$Auth = new Authentication();
$FalseCounter = 0;
$TrueCounter = 0;
while ($Incline < $Max){
$PasswordString = "1";
$Encrypted_Pass = $Auth->Hash_Password($PasswordString);
$Check = crypt($PasswordString,$Encrypted_Pass['Salt']);
if ($Check === $Encrypted_Pass['Password']){
$TrueCounter++;
}else{
$FalseCounter++;
}
if ($Incline === $Max){
break;
}
$Incline++;
}
echo 'Of '.$Max.' Checks '.$FalseCounter.' False Returns & '.$TrueCounter.' True Returns';
$Auth->Hash_Password 为:
public $Salt = null;
public function SetSalt(){
$ByteSize = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
$Salt = mcrypt_create_iv($ByteSize, MCRYPT_DEV_RANDOM);
$this->Salt = $Salt;
if (!is_null($this->Salt)){
return true;
}
return false;
}
public function Hash_Password($Password){
$this->SetSalt();
$Return_Array = array();
$Return_Array['Salt'] = $this->Salt;
$Return_Array['Password'] = crypt($Password,$this->Salt);
return $Return_Array;
}
现在,在显示代码之后。我的输出如下(多次刷新)
Of 4000 Checks 22 False Returns & 3978 True Returns
Of 4000 Checks 15 False Returns & 3985 True Returns
Of 4000 Checks 15 False Returns & 3985 True Returns
Of 4000 Checks 10 False Returns & 3990 True Returns
Of 4000 Checks 6 False Returns & 3994 True Returns
Of 10000 Checks 40 False Returns & 9960 True Returns
Of 10000 Checks 43 False Returns & 9957 True Returns
Of 50000 Checks 196 False Returns & 49804 True Returns
尽管失败率很小。问题仍然存在。关于密码加密,这不应该是所有密码比较的100%吗?
因此,总体问题是:什么会导致这种影响?这可能是我的编码吗?还是完全完美的 PHP 中的缺陷?
最佳答案
似乎 crypt 受到“空字节中毒”的影响。所有测试都将通过,如果您将 SetSalt 方法更改为:
<?php
public function SetSalt()
{
$ByteSize = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
do {
$Salt = mcrypt_create_iv($ByteSize, MCRYPT_DEV_RANDOM);
// Remove null byte from salt
$this->Salt = str_replace(chr(0), '', $Salt);
} while ($this->Salt !== $Salt); // Retry until salt without null byte is generated
if (!is_null($this->Salt)) {
return true;
}
return false;
}
之后所有的测试都通过了:
$ php crypt_test.php
Of 4000 Checks 0 False Returns & 4000 True Returns
如果您想阅读更多关于空字节的信息,您可以从这里开始:http://www.madirish.net/401
为了更好地说明,这里是失败测试的示例输出:
string(34) "$1$iyJhOmt2$23uOXEcjWr2GcjSMqKpHk0"
array(2) {
'Salt' =>
string(16) "\000g-Ŕ=(
��A��n0"
'Password' =>
string(34) "$1$QCbFiEDR$g3RDS7LK3m88K7XPqjF5O."
}
您可以在此处看到空字节:\0。
对于所有懒惰的人,这里是我使用的完整(固定)测试脚本;)
<?php
class Authentication
{
public $Salt = null;
public function SetSalt()
{
$ByteSize = mcrypt_get_iv_size(MCRYPT_CAST_256, MCRYPT_MODE_CFB);
do {
$Salt = mcrypt_create_iv($ByteSize, MCRYPT_DEV_RANDOM);
// Remove null byte from salt
$this->Salt = str_replace(chr(0), '', $Salt);
} while ($this->Salt !== $Salt);
if (!is_null($this->Salt)) {
return true;
}
return false;
}
public function Hash_Password($Password)
{
$this->SetSalt();
$Return_Array = array();
$Return_Array['Salt'] = $this->Salt;
$Return_Array['Password'] = crypt($Password, $this->Salt);
return $Return_Array;
}
}
$Incline = 0;
$Max = 4000;
$Auth = new Authentication();
$FalseCounter = 0;
$TrueCounter = 0;
while ($Incline < $Max) {
$PasswordString = "1";
$Encrypted_Pass = $Auth->Hash_Password($PasswordString);
$Check = crypt($PasswordString, $Encrypted_Pass['Salt']);
if ($Check === $Encrypted_Pass['Password']) {
$TrueCounter++;
} else {
var_dump($Encrypted_Pass, $Check);
$FalseCounter++;
}
if ($Incline === $Max) {
break;
}
$Incline++;
}
echo 'Of ' . $Max . ' Checks ' . $FalseCounter . ' False Returns & ' . $TrueCounter . ' True Returns' . "\n";
快乐编码
关于php - 什么会导致 crypt 产生错误的验证?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32161460/
类classAprivatedeffooputs:fooendpublicdefbarputs:barendprivatedefzimputs:zimendprotecteddefdibputs:dibendendA的实例a=A.new测试a.foorescueputs:faila.barrescueputs:faila.zimrescueputs:faila.dibrescueputs:faila.gazrescueputs:fail测试输出failbarfailfailfail.发送测试[:foo,:bar,:zim,:dib,:gaz].each{|m|a.send(m)resc
给定这段代码defcreate@upgrades=User.update_all(["role=?","upgraded"],:id=>params[:upgrade])redirect_toadmin_upgrades_path,:notice=>"Successfullyupgradeduser."end我如何在该操作中实际验证它们是否已保存或未重定向到适当的页面和消息? 最佳答案 在Rails3中,update_all不返回任何有意义的信息,除了已更新的记录数(这可能取决于您的DBMS是否返回该信息)。http://ar.ru
我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co
我想安装一个带有一些身份验证的私有(private)Rubygem服务器。我希望能够使用公共(public)Ubuntu服务器托管内部gem。我读到了http://docs.rubygems.org/read/chapter/18.但是那个没有身份验证-如我所见。然后我读到了https://github.com/cwninja/geminabox.但是当我使用基本身份验证(他们在他们的Wiki中有)时,它会提示从我的服务器获取源。所以。如何制作带有身份验证的私有(private)Rubygem服务器?这是不可能的吗?谢谢。编辑:Geminabox问题。我尝试“捆绑”以安装新的gem..
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我正在使用的第三方API的文档状态:"[O]urAPIonlyacceptspaddedBase64encodedstrings."什么是“填充的Base64编码字符串”以及如何在Ruby中生成它们。下面的代码是我第一次尝试创建转换为Base64的JSON格式数据。xa=Base64.encode64(a.to_json) 最佳答案 他们说的padding其实就是Base64本身的一部分。它是末尾的“=”和“==”。Base64将3个字节的数据包编码为4个编码字符。所以如果你的输入数据有长度n和n%3=1=>"=="末尾用于填充n%
我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i
为什么4.1%2返回0.0999999999999996?但是4.2%2==0.2。 最佳答案 参见此处:WhatEveryProgrammerShouldKnowAboutFloating-PointArithmetic实数是无限的。计算机使用的位数有限(今天是32位、64位)。因此计算机进行的浮点运算不能代表所有的实数。0.1是这些数字之一。请注意,这不是与Ruby相关的问题,而是与所有编程语言相关的问题,因为它来自计算机表示实数的方式。 关于ruby-为什么4.1%2使用Ruby返
我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss