我已经看到了一些类似的问题,这些问题似乎并不能完全解决我的确切用例,我认为我已经找到了答案,但是在安全性、RSA 和几乎所有方面我都是菜鸟与之相关的一切。我对这些概念有基本的了解,但到目前为止我所做的所有实际实现都是关于编辑别人的代码而不是生成我自己的代码。无论如何,这就是我所在的位置:
我知道 Javascript 是一个天生不好加密的地方。有人可能会在您的响应中充当中间人并破坏 JS,因此您最终将通过网络发送未加密的数据。它应该通过 HTTPS SSL/TLS 连接来完成,但是这种托管需要花钱,而且官方签名的证书也是如此,实际上应该与连接一起使用。
话虽这么说,我认为我将这样做的方式绕过了 JS 加密的中间人弱点,因为我只为一个 RESTful 加密一件事(密码哈希)服务调用,然后仅使用该密码哈希对来自客户端的请求进行签名,以便将它们验证为来自请求声明的用户。这意味着 JS 只负责在创建用户帐户时加密密码哈希一次,如果服务器无法解码该密码,则它知道它已经拥有。
我还要保存一些客户信息,尤其是 $_SERVER['REMOTE_ADDR']以保证某人不会 M-i-t-M 注册交换本身。
我正在使用 PHP 的 openssl_pkey_生成非对称 key 的函数,以及 Cryptico客户端的库。我的计划是让用户向 REST 服务发送“预注册”请求,这将导致服务器生成 key ,将私钥和客户端信息存储在电子邮件地址索引的数据库中,然后响应与公钥。
然后,客户端将使用公钥加密用户的密码哈希,并将其作为另一种请求类型发送到 REST 服务以完成注册。服务器将解密并保存密码哈希,使客户端信息和私钥无效,因此无法使用该信息进行进一步的注册,然后返回 200状态码。
要登录,用户将输入他们的电子邮件地址和密码,密码将在注册期间被散列,附加到请求正文,并再次散列以签署对登录端点的请求,该端点将尝试将存储的散列附加到请求正文并对其进行哈希处理以根据请求中的签名验证签名,从而对用户进行身份验证。对服务的进一步数据请求将遵循相同的身份验证过程。
我错过了任何明显的漏洞吗?是否可以欺骗 $_SERVER['REMOTE_ADDR']对特定事物的值(value)?我不需要IP地址准确或与用户登录时相同,我只需要知道“预注册”并获得公钥的同一台机器跟进并完成注册而不是劫机者使用窥探的公钥为他们完成注册。当然,我猜如果他们能做到这一点,他们在创建时就已经劫持了无法恢复的帐户,并且合法用户将无法使用自己的密码完成注册,这也可以。
底线 ,除非我购买真正的 SSL 主机,否则有人还能破解我的服务吗?我是否绕过了 Javascript 作为加密工具的弱点?
当我编写和调试我的代码时,如果有人想使用它,我会在这里发布。如果我让我的网站受到任何形式的攻击,请告诉我。
这些函数根据 header 中的散列验证客户端请求、生成私钥、将其保存到数据库、使用公钥响应以及解密和检查密码散列。
public function validate($requestBody = '',$signature = '',$url = '',$timestamp = '') {
if (is_array($requestBody)) {
if (empty($requestBody['signature'])) { return false; }
if (empty($requestBody['timestamp'])) { return false; }
if ($requestBody['requestBody'] === null) { return false; }
$signature = $requestBody['signature'];
$timestamp = $requestBody['timestamp'];
$requestBody = $requestBody['requestBody'];
}
if (($requestBody === null) || empty($signature) || empty($timestamp)) { return false; }
$user = $this->get();
if (count($user) !== 1 || empty($user)) { return false; }
$user = $user[0];
if ($signature !== md5("{$user['pwHash']}:{$this->primaryKey}:$requestBody:$url:$timestamp")) { return false; }
User::$isAuthenticated = $this->primaryKey;
return $requestBody;
}
public function register($emailAddress = '',$cipher = '') {
if (is_array($emailAddress)) {
if (empty($emailAddress['cipher'])) { return false; }
if (empty($emailAddress['email'])) { return false; }
$cipher = $emailAddress['cipher'];
$emailAddress = $emailAddress['email'];
}
if (empty($emailAddress) || empty($cipher)) { return false; }
$this->primaryKey = $emailAddress;
$user = $this->get();
if (count($user) !== 1 || empty($user)) { return false; }
$user = $user[0];
if (!openssl_private_decrypt(base64_decode($cipher),$user['pwHash'],$user['privateKey'])) { return false; }
if (md5($user['pwHash'].":/api/preRegister") !== $user['session']) { return false; }
$user['session'] = 0;
if ($this->put($user) !== 1) { return false; }
$this->primaryKey = $emailAddress;
User::$isAuthenticated = $this->primaryKey;
return $this->getProfile();
}
public function preRegister($emailAddress = '',$signature = '') {
if (is_array($emailAddress)) {
if (empty($emailAddress['signature'])) { return false; }
if (empty($emailAddress['email'])) { return false; }
$signature = $emailAddress['signature'];
$emailAddress = $emailAddress['email'];
}
if (empty($emailAddress) || empty($signature)) { return false; }
$this->primaryKey = $emailAddress;
$response = $this->makeUserKey($signature);
if (empty($response)) { return false; }
$response['emailAddress'] = $emailAddress;
return $response;
}
private function makeUserKey($signature = '') {
if (empty($signature)) { return false; }
$config = array();
$config['digest_alg'] = 'sha256';
$config['private_key_bits'] = 1024;
$config['private_key_type'] = OPENSSL_KEYTYPE_RSA;
$key = openssl_pkey_new($config);
if (!openssl_pkey_export($key,$privateKey)) { return false; }
if (!$keyDetails = openssl_pkey_get_details($key)) { return false; }
$keyData = array();
$keyData['publicKey'] = $keyDetails['key'];
$keyData['privateKey'] = $privateKey;
$keyData['session'] = $signature;
if (!$this->post($keyData)) { return false; }
$publicKey = openssl_get_publickey($keyData['publicKey']);
$publicKeyHash = md5($keyData['publicKey']);
if (!openssl_sign($publicKeyHash,$signedKey,$privateKey)) { return false; }
if (openssl_verify($publicKeyHash,$signedKey,$publicKey) !== 1) { return false; }
$keyData['signedKey'] = base64_encode($signedKey);
$keyData['rsa'] = base64_encode($keyDetails['rsa']['n']).'|'.bin2hex($keyDetails['rsa']['e']);
unset($keyData['privateKey']);
unset($keyData['session']);
return $keyData;
}
最佳答案
您要做的是用自定义 JavaScript 替换对由证书颁发机构签名的 SSL 证书的需求。我不是安全专家,但据我所知,简单的答案是这是不可能的。
基本事实是,在公共(public)互联网上,服务器无法信任客户端所说的话,客户端也无法信任服务器所说的话,这正是由于中间人攻击。之所以需要证书颁发机构,首先是为了建立某种公正的信任基础。 CA 是 carefully vetted由浏览器供应商提供,它是目前公共(public)互联网上唯一可用的信任,尽管它肯定是 not perfect .
关于php - 基于 Javascript 的 SSL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22035821/
导读:随着叮咚买菜业务的发展,不同的业务场景对数据分析提出了不同的需求,他们希望引入一款实时OLAP数据库,构建一个灵活的多维实时查询和分析的平台,统一数据的接入和查询方案,解决各业务线对数据高效实时查询和精细化运营的需求。经过调研选型,最终引入ApacheDoris作为最终的OLAP分析引擎,Doris作为核心的OLAP引擎支持复杂地分析操作、提供多维的数据视图,在叮咚买菜数十个业务场景中广泛应用。作者|叮咚买菜资深数据工程师韩青叮咚买菜创立于2017年5月,是一家专注美好食物的创业公司。叮咚买菜专注吃的事业,为满足更多人“想吃什么”而努力,通过美好食材的供应、美好滋味的开发以及美食品牌的孵
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
需求:要创建虚拟机,就需要给他提供一个虚拟的磁盘,我们就在/opt目录下创建一个10G大小的raw格式的虚拟磁盘CentOS-7-x86_64.raw命令格式:qemu-imgcreate-f磁盘格式磁盘名称磁盘大小qemu-imgcreate-f磁盘格式-o?1.创建磁盘qemu-imgcreate-fraw/opt/CentOS-7-x86_64.raw10G执行效果#ls/opt/CentOS-7-x86_64.raw2.安装虚拟机使用virt-install命令,基于我们提供的系统镜像和虚拟磁盘来创建一个虚拟机,另外在创建虚拟机之前,提前打开vnc客户端,在创建虚拟机的时候,通过vnc
我遇到了一个非常奇怪的问题,我很难解决。在我看来,我有一个与data-remote="true"和data-method="delete"的链接。当我单击该链接时,我可以看到对我的Rails服务器的DELETE请求。返回的JS代码会更改此链接的属性,其中包括href和data-method。再次单击此链接后,我的服务器收到了对新href的请求,但使用的是旧的data-method,即使我已将其从DELETE到POST(它仍然发送一个DELETE请求)。但是,如果我刷新页面,HTML与"new"HTML相同(随返回的JS发生变化),但它实际上发送了正确的请求类型。这就是这个问题令我困惑的
我正在寻找用于Rails的优质管理插件。似乎大多数现有的插件/gem(例如“restful_authentication”、“acts_as_authenticated”)都围绕着self注册等展开。但是,我正在寻找一种功能齐全的基于管理/管理角色的解决方案——但不是简单地附加到另一个非基于角色的解决方案。如果我找不到,我想我会自己动手......只是不想重新发明轮子。 最佳答案 RyanBates最近做了两个关于授权的railscast(注意身份验证和授权之间的区别;身份验证检查用户是否如她所说的那样,授权检查用户是否有权访问资源
我正在尝试在ruby脚本中连接到服务器https://www.xpiron.com/schedule。但是,当我尝试连接时:require'open-uri'doc=open('https://www.xpiron.com/schedule')我收到以下错误消息:OpenSSL::SSL::SSLError:SSL_connectreturned=1errno=0state=SSLv2/v3readserverhelloA:sslv3alertunexpectedmessagefrom/usr/local/lib/ruby/1.9.1/net/http.rb:678:in`conn
我正在使用Rails3.2.6和Stipe进行支付。是否有可能在不购买ssl证书的情况下进行付款。我可以使用Stripe页面作为我的支付页面吗? 最佳答案 您可以使用stripe.js在技术上跳过SSL但我强烈建议您设置SSL。它所做的是将信用卡信息直接传递给stripe,然后stripe会给你一个token,用于实际进行收费。这样做意味着信用卡信息永远不会接触您的服务器,您不必担心PCI合规性。但是,您仍应设置SSL以防止中间人攻击。您可以在https://stripe.com/docs/tutorials/forms找到有关如何
我正在根据Rakefile中的现有测试文件动态生成测试任务。假设您有各种以模式命名的单元测试文件test_.rb.所以我正在做的是创建一个以“测试”命名空间内的文件名命名的任务。使用下面的代码,我可以用raketest:调用所有测试require'rake/testtask'task:default=>'test:all'namespace:testdodesc"Runalltests"Rake::TestTask.new(:all)do|t|t.test_files=FileList['test_*.rb']endFileList['test_*.rb'].eachdo|task|n
我有这个:AccountSummary我想单击该链接,但在使用link_to时出现错误。我试过:bot.click(page.link_with(:href=>/menu_home/))bot.click(page.link_with(:class=>'top_level_active'))bot.click(page.link_with(:href=>/AccountSummary/))我得到的错误是:NoMethodError:nil:NilClass的未定义方法“[]” 最佳答案 那是一个javascript链接。Mechan
尝试通过SSL连接到ImgurAPI时出现错误。这是代码和错误:API_URI=URI.parse('https://api.imgur.com')API_PUBLIC_KEY='Client-ID--'ENDPOINTS={:image=>'/3/image',:gallery=>'/3/gallery'}#Public:Uploadanimage##args-Theimagepathfortheimagetoupload#defupload(image_path)http=Net::HTTP.new(API_URI.host)http.use_ssl=truehttp.verify