背景
我已经实现了一个 HTTPS 服务器,它位于一个硬件内部,用于设备的安全远程配置。为了实现这一点,我使用了现有的轻量级嵌入式 TCP/IP 堆栈以及开源 SSL 库。位于其之上的 Web 服务器完全由我从头开始编写。(这可能看起来像是对轮子的重新发明,但就我们的目的而言,它需要非常轻量级并且具有非常狭窄的特定功能集。例如,与我们正在使用的嵌入式 RTOS 以及 ROM“文件系统”的兼容性。这是一个只有几百 KB 可用于 HTTP(S) 会话和 SSL 上下文的系统,而不是多少兆字节。在考虑了所有因素并查看了各种其他产品之后,创建我自己的产品是有意义的)。该 Web 服务器只需要支持 5 到 10 个同时套接字连接(即 5 到 10 个并发或持久 HTTP 连接),这大约是硬件可以处理的数量。这很好,因为它是专为一两个人访问和管理盒子而设计的。
目前,它现在一切正常。我已经对其进行了编码,以实现我认为 HTTP 1.1 所必需的尽可能多的 RFC2616。目前,它只是监听五个 HTTPS 端口(443),我还没有实现任何从端口 80 重定向的东西。
第一个问题 - 重定向
我看过无数关于从 HTTP 重定向到 HTTPS 的文章,但我读到的所有内容都涉及如何配置现有的和传统的 Web 服务器来执行此操作。我想要解决的是在协议级别使用了哪些技术,因为我必须以编程方式实现这一点。
常见的方法似乎是发出 301 / 302 响应。所以,我想到的策略是,假设我有八个同时请求的资源:
在端口 443 上侦听 HTTPS 连接。最多可同时使用六个 HTTPS 连接(六个套接字)。
在端口 80 上侦听 HTTP 连接,最多有两个 HTTP 连接(因此端口 80 上有两个套接字)可用。对于端口 80 上的套接字,不会真正访问真正的 Web 服务器。相反,我会一直从套接字读取,直到看到
\r\n\r\n
或\n\n
看到(指示请求标头结束),然后发回 301(或 302)响应,在我的代码中它几乎是一个硬编码const char*
字符串。然后,关闭套接字。这两个端口 80 套接字的存在纯粹是为了重定向。
这个策略听起来合理吗?
目前我唯一不确定的是在 301 / 302 响应中包含重定向 URL。这个硬件“盒子”是一个可以放在房子里或路由器后面某处的设备,可能通过动态 DNS 服务等访问。那么,我将如何以编程方式确定它的“外部世界”等效 HTTPS URL?也许通过结合使用请求 URI 中的内容和host:
原始 HTTP 请求标头的字段?
如果上面有任何问题,那么我的下一个最佳想法是返回一小段 HTML,其中包含一些 JavaScript,通过从浏览器获取 URL 来执行 HTTPS 重定向(特别是我会使用哪些 JavaScript 方法打电话来做这件事我不记得了,但我已经做了很久了)。(目前我还不确定 SSL 证书到底是如何工作的,因为没有可以指定的特定域,但我稍后会越过那座桥,也许在一个单独的 SO 问题中。)
第二个问题 - 提供 HTTP 和 HTTPS
这可能更像是一个设计问题,或者取决于客户想要什么,而不是一个编程问题——但我想我还是把它放在这里看看人们有什么意见。我的问题是客户只是简单地声明盒子“应该有 SSL”,但仅此而已。例如,我不知道他们是否期望能够为最终用户提供是否使用 SSL 的选择。现在在真正问他们之前,我只是在预测可能会被问到什么,我想事先用一些知识和答案武装自己。换句话说,写规范的人为这个“只想看挂锁”和“想要SSL”,这显然是件好事;
首先,我知道 SSL 没有半途而废的解决方案:你要么需要全部,要么什么都没有。换句话说,假设我决定尝试通过 HTTPS 提供重要的东西来减少我的小处理器必须做的工作,但我通过 HTTP 提供图像和 CSS 文件。在做了一些阅读之后,我现在确切地知道为什么这是一个绝对的禁忌,原因有很多。
但是,如果我让最终用户能够在某个初始登录页面选择 HTTPS 或 HTTP 会怎样?选择“HTTPS”将重定向到安全的 HTTPS 登录页面。例如,如果用户在从手机访问盒子时为了提高访问速度而选择牺牲安全性,这可能是一个有用的选项。此初始页面可能提供“安全登录”和“标准不安全登录 - 不建议”或类似内容。显然,就用户而言,这会带来一个漏洞,但它是否也会危及 SSL 连接?我的意思是,由于这个初始登录页面必须通过 HTTP 提供服务,因此理论上攻击者可能会破坏它,以便交换按钮——诸如此类。因此,HTTPS应该意味着HTTPS从一开始就对吗?鉴于我已经设法将 HTTPS 硬塞到这个东西中并使它工作,并且考虑到它是专门为与现代浏览器(IE8/9,FF)一起使用而设计的,那么正常的 HTTP 访问应该是什么实际的原因呢?作为替代方案提供?