草庐IT

一文搞懂HTTP与HTTPS

机器学习Zero 2023-04-18 原文

HTTP与HTTPs

1. 基本概念

1.1 HTTP

超文本传输协议(HTTP,HyperText Transfer Protocol),是客户端浏览器或其他程序与Web服务器之间的应用层通信协议,一般使用80端口。

HTTP请求过程中,客户端与服务器之间没有任何身份确认的过程,数据全部明文传输,易遭到黑客的攻击。黑客可“劫持”客户端发出的请求,并冒充服务器返回任意信息给客户端,且不被客户端察觉。

HTTP传输面临的风险包括:

  • 截取:通信内容被获取
  • 篡改:通信内容被修改
  • 伪造:非法实体冒充合法实体参与通信

1.2 HTTPs

安全超文本传输协议(HTTPS,Hypertext Transfer Protocol Secure),由HTTP+SSL/TLS构建的可进行加密传输、身份认证的网络协议,一般使用443端口

安全套接字层(SSL,Secure Socket Layer)/传输层安全(TLS,Transport Layer Security)协议位于应用层和TCP层之间。应用层数据传递给SSL/TLS实现传输加密与身份认证,需要到CA申请证书。

2. 非对称加密+对称加密方案

2.1 实现方案

为了方防止通信内容被获取,可对传输内容进行加密。直接使用对称加密算法,存在密钥传输与管理上的问题,一般采用对称加密方式对通信内容进行加密,而采用非对称加密方式实现对称加密的密钥传递

  • 客户端:发起HTTPS请求
  • 服务器:生成公钥/私钥对 Pu/Pr,并把公钥发给客户端
  • 客户端:生成随机数K作为会话密钥,用收到的公钥Pu加密后发送给服务器
  • 服务器:使用私钥Pr解密,得到会话密钥K

客户端和服务器通过对称加密算法,使用会话密钥K对通信数据进行加密


上述步骤中的会话密钥由客户端生成并且用服务器的公钥加密后发送至服务器,由于只有服务器才有私钥,因此也只有服务器才能解开客户端发送的密钥。

要确保传输的会话密钥只被服务器解密,就须确保用于加密会话密钥的公钥一定由服务器下发,绝对不可能被第三方篡改过。

2.2 中间人攻击

如果在数据传输过程中,中间人劫持到了数据,就可以在通信双方都不会发现异常的情况下,中间人通过将服务器的公钥替换为自己伪造的公钥,进而得到会话密钥K,其根本原因是浏览器无法确认收到的公钥是否来自服务器

  • 客户端:发起HTTPS请求
  • 服务器:生成公钥/私钥对 Pu/Pr,并把公钥发给客户端
  • 中间人:劫持到服务器发送的公钥Pu,并保存下来,然后将公钥Pu替换成自己伪造的公钥Pu‘(对应私钥为Pr’)发送给客户端。
  • 客户端:生成随机数K作为会话密钥,用收到的公钥Pu‘加密K发送给服务器
  • 中间人:劫持到秘文后,用私钥Pr’解密得到会话密钥K,再用服务器公钥Pu加密后传给服务器。
  • 服务器:使用私钥Pr解密,得到会话密钥K

3. 基于SSL的实现

3.1 实现方案

要保客户端接收到的公钥为服务器真正的公钥(而不是中间人伪造的公钥),就需要引入公钥基础设施(PKI,Public Key Infrastructure),通过PKI的认证机构CA(Certificate Authority)为服务器签发的数字证书来实现。

服务器收到客户的https请求后,向客户端发送SSL证书,既解决了公钥获取问题,又解决了“中间人攻击”问题。SSL证书中包括:

  • 证书的发布机构CA
  • CA的数字签名(通过CA的私钥对证书的数字摘要加密生成)
  • 证书的有效期
  • 证书持有者身份信息
  • 证书持有者的公钥

客户端接受到服务端发来的SSL证书,对证书进行校验,以浏览器为例说明如下:

(1)浏览器读取证书中的证书所有者、有效期等信息,并进行校验

(2)浏览器查找操作系统中内置的受信任证书发布机构CA,与服务器发来的证书中的颁发者CA比对,用于校验证书是否为合法机构颁发

(3)如果找不到,浏览器就会报错,说明服务器发来的证书是不可信任的

(4)如果找到,浏览器验证CA的数字签名(使用CA的公钥对服务器发来的证书中的CA数字签名进行解密),得到证书的hash值

(5)浏览器使用相同的hash算法计算出服务器发来的证书的hash值,将这个计算的hash值与证书中hash值做对比

(6)对比结果一致,则证明服务器发来的证书合法

(7)协商生成会话密钥,并用会话密钥加密通信数据

3.2 HTTPs的密钥协商

HTTPS一般采用RSA或者DH算法协商预主密钥(PreMaster Secret),通过预主密钥生成主密钥(Master secret),再用主密钥用来生成各类加密算法密钥。

(1)RSA

  • 客户端向服务器端发起连接请求。
  • 服务器端生成一个RSA密钥对,并将公钥发送给客户端。
  • 客户端通过随机数生成器生成一个预备主密钥,用服务器的公钥加密并发送给服务器端。
  • 服务器解密预备主密钥,假如能够正确解密,则说明客户端和服务器端共同协商出一个预备主密钥。

(2)DH 算法

DH 算法的预备主密钥是客户端和服务器端共同计算出来的,因此是一致的。

  • 客户端向服务器端发起连接请求。
  • 服务器端生成一个RSA密钥对,并将公钥发送给客户端。
  • 服务器端生成DH参数和服务器DH密钥对,用RSA私钥签名DH参数和服务器 DH 公钥,将签名值、DH 参数、服务器 DH公钥发送给客户端。
  • 客户端通过服务器RSA的公钥验证签名,获取到PH参数和服务器DH公钥。客户端通过DH参数生成客户端的DH密钥对,并将客户端DH公钥发送给服务器端。
  • 客户端通过客户端 DH 私钥和服务器端 DH 公钥计算出预备主密钥。
  • 服务器端接收到客户端的DH公钥,结合服务器的DH私钥计算出预备主密钥。

有关一文搞懂HTTP与HTTPS的更多相关文章

  1. ruby - 如何模拟 Net::HTTP::Post? - 2

    是的,我知道最好使用webmock,但我想知道如何在RSpec中模拟此方法:defmethod_to_testurl=URI.parseurireq=Net::HTTP::Post.newurl.pathres=Net::HTTP.start(url.host,url.port)do|http|http.requestreq,foo:1endresend这是RSpec:let(:uri){'http://example.com'}specify'HTTPcall'dohttp=mock:httpNet::HTTP.stub!(:start).and_yieldhttphttp.shou

  2. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  3. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting - 2

    1.错误信息:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:requestcanceledwhilewaitingforconnection(Client.Timeoutexceededwhileawaitingheaders)或者:Errorresponsefromdaemon:Gethttps://registry-1.docker.io/v2/:net/http:TLShandshaketimeout2.报错原因:docker使用的镜像网址默认为国外,下载容易超时,需要修改成国内镜像地址(首先阿里

  4. ruby-on-rails - Rails - 从命名路由中提取 HTTP 动词 - 2

    Rails中有没有一种方法可以提取与路由关联的HTTP动词?例如,给定这样的路线:将“users”匹配到:“users#show”,通过:[:get,:post]我能实现这样的目标吗?users_path.respond_to?(:get)(显然#respond_to不是正确的方法)我最接近的是通过执行以下操作,但它似乎并不令人满意。Rails.application.routes.routes.named_routes["users"].constraints[:request_method]#=>/^GET$/对于上下文,我有一个设置cookie然后执行redirect_to:ba

  5. ruby-on-rails - Heroku 吃掉了我的自定义 HTTP header - 2

    我正在使用Heroku(heroku.com)来部署我的Rails应用程序,并且正在构建一个iPhone客户端来与之交互。我的目的是将手机的唯一设备标识符作为HTTPheader传递给应用程序以进行身份​​验证。当我在本地测试时,我的header通过得很好,但在Heroku上它似乎去掉了我的自定义header。我用ruby​​脚本验证:url=URI.parse('http://#{myapp}.heroku.com/')#url=URI.parse('http://localhost:3000/')req=Net::HTTP::Post.new(url.path)#boguspara

  6. ruby-on-rails - 使用 HTTP.get_response 检索 Facebook 访问 token 时出现 Rails EOF 错误 - 2

    我试图在我的网站上实现使用Facebook登录功能,但在尝试从Facebook取回访问token时遇到障碍。这是我的代码:ifparams[:error_reason]=="user_denied"thenflash[:error]="TologinwithFacebook,youmustclick'Allow'toletthesiteaccessyourinformation"redirect_to:loginelsifparams[:code]thentoken_uri=URI.parse("https://graph.facebook.com/oauth/access_token

  7. ruby - HTTP 请求中的用户代理,Ruby - 2

    我是Ruby的新手。我试过查看在线文档,但没有找到任何有效的方法。我想在以下HTTP请求botget_response()和get()中包含一个用户代理。有人可以指出我正确的方向吗?#PreliminarycheckthatProggitisupcheck=Net::HTTP.get_response(URI.parse(proggit_url))ifcheck.code!="200"puts"ErrorcontactingProggit"returnend#Attempttogetthejsonresponse=Net::HTTP.get(URI.parse(proggit_url)

  8. ruby - 如何使用 Ruby HTTP::Net 处理 404 错误? - 2

    我正在尝试解析网页,但有时会收到404错误。这是我用来获取网页的代码:result=Net::HTTP::getURI.parse(URI.escape(url))如何测试result是否为404错误代码? 最佳答案 像这样重写你的代码:uri=URI.parse(url)result=Net::HTTP.start(uri.host,uri.port){|http|http.get(uri.path)}putsresult.codeputsresult.body这将打印状态码和正文。

  9. ruby - 让 bundler 使用 http : instead of git:? - 2

    我正在安装gitlabhq,并且在Gemfile中有对某些资源的“git://...”的引用。但是,我在公司防火墙后面,所以我必须使用http://。我可以手动编辑Gemfile,但我想知道是否有另一种方法告诉bundler使用http://作为git存储库? 最佳答案 您可以通过运行gitconfig--globalurl."https://".insteadOfgit://或通过将以下内容添加到~/.gitconfig:[url"https://"]insteadOf=git://

  10. ruby - 如何捕获所有 HTTP 流量(本地代理) - 2

    我希望访问我机器上的所有HTTP流量(我的Windows机器-不是服务器)。据我了解,拥有一个本地代理是所有流量路线的必经之路。我一直在谷歌搜索但未能找到任何资源(关于Ruby)来帮助我。非常感谢任何提示或链接。 最佳答案 WEBrick中有一个HTTP代理(Rubystdlib的一部分)和here's一个实现示例。如果你喜欢生活在边缘,还有em-proxy伊利亚·格里戈里克。这postIlya暗示它似乎确实需要一些调整来解决您的问题。 关于ruby-如何捕获所有HTTP流量(本地代理)

随机推荐