Category Archives

18 Articles

用 OpenResty 写了一个 SNI 代理

0   8442 转为繁体

功能类似于dlundquist/sniproxy

推荐 OpenResty 加上 stream 模块和 ngx_stream_lua_module 模块。在 1.9.15.1 上测试通过。

示例配置:

A Lua table sni_rules should be defined in the init_worker_by_lua_block directive.

The key can be either whole host name or regular expression. Use . for a default host name. If no entry is matched, connection will be closed.

The value is a table containing host name and port. If host is set to nil, the server_name in SNI will be used. If the port is not defined or set to nil, 443 will be used.

Rules are applied with the priority as its occurrence sequence in the table. In the example above, twitter.com will match the third rule rather than the fourth.

If the protocol version is less than TLSv1 (eg. SSLv3, SSLv2), connection will be closed, since SNI extension is not supported in these versions.

Let’s Encrypt集中化管理

9   8516 转为繁体

Let’s Encrypt的证书签发原理实际上和传统的PKI一样,只不过自动化完成了生成CSR和私钥、提交CSR、取回证书的过程。

此外还要验证域名所属,这一部分和传统的签发机构是一样的,不过传统的签发机构还允许我们使用域名whois中填写的邮箱来验证,而Letsencrypt貌似只能通过http challenge的方式来验证。即和验证服务器约定一个uri和随机字符串,验证服务器请求这一uri,如果得到的内容和约定的随机字符串相同,则验证通过。如图所示:

letsencrypt_howitworks

官网上抄的)

这意味着我们得在每台部署https的前端的负载均衡服务器上都装一个letencrypt工具。有没有什么集中化管理的办法的呢?

实际上,由于challenge的uri的有规律,我们可以将前端服务器收到的这类请求代理到同一台专门用来签发、更新证书的服务器上。如图所示:

letsencrypt_howitworks_proxypass

  1. 当在服务器B上发起域名a.example.com新的签发请求后,Let’s Encrypt的签发服务器返回一个challange uri (8303)和response (ed98)。
  2. 服务器B使用webroot插件将这个uri和response写入本地磁盘上对应的文件。
  3. Let’s Encrypt的签发服务器为了验证example.com的所属,查询到example.com指向前端服务器A,于是发送一个HTTP请求/.well-known/acme-challenge/8303到服务器A
  4. 服务器A反代这一请求到服务器B
  5. B读取刚才第二步时写入到response,返回到A;A返回到Let’s Encrypt的签发服务器
  6. 验证成功,发证!

然后,我们只要从服务器A上取回存储在B上到证书就可以了。可以在B上做一个RESTful的api。注意要配置allow和deny。

A服务器(前端)的nginx配置如下:

B服务器的nginx配置如下:

然后在B上运行:

搭建一个不被审查的串流站点

17   44987 转为繁体

原标题:被害妄想症该如何生存

先看配置:

假设:

审查机关拥有运营商级别的入侵检测设备(比如GFW)

说明:

  1. 全站使用https,关闭SSLv3,关闭弱加密组件
  2. default_server开启80端口,使用自签名证书;真实需要访问的域名(example.com)必须使用有效的证书,或者在本地信任根证书。注意example.com不能开启80端口,且与default_server使用的证书不能相同。不要使用泛域名证书。这是为了防止审查机关通过直连IP查看返回的证书中的Common Name来得到真实域名。这样配置之后,直连IP https://xxx.xxx.xxx.xxx默认是返回自签名证书,无法得到真实example.com。
  3. 选择性开启autoindex,通过cookie鉴别。注意也可以通过HTTP Basic Authenication认证。对匹配文件夹的uri(”/”结尾)做认证,示例中只有带cookie coo=coo的请求才会返回autoindex,否则返回404。
  4. 在location /中禁用目录末尾自动加斜杠,因为如果自动加斜杠,审查机关可以通过暴力猜测出服务器上有哪些目录确实存在(返回了301到末尾加/的url)。方法是if (-d $request_filename)返回404。

nginx 批量配置同步

0   68104 转为繁体

在编译了lua-nginx-module的nginx上,可以方便地使用shared dict特性,在不reload配置文件的情况下实现配置同步。

由于shared dict使用一块共享内存,因此所有worker均可读写,也就不存在一致性的问题。

使用shared dict

Read More

nginx/openresty的一些记录

28   36300 转为繁体

日志

屏蔽user-agent并屏蔽日志

不屏蔽user-agent(允许其访问),但屏蔽日志

按uri屏蔽日志(可以和上面的按user-agent用同一个变量来同时过滤uri和user-agent)

 

Header

按mime type设置缓存时间

防攻击

简单的无状态cookie challenge(需要lua-nginx-module)

crawlers块中可以手动填写要屏蔽的IP

将其中的s改成随机字符串+时间戳可以变成有状态版本(需使用redis/memcached/shared memory存储生成的随机字符串)

将set-cookie改成通过js生成cookie可以变成javascript challenge,注意要在js里加上浏览器上下文判断,如var cookie=location.protocol?cookie:””; 或者DOM操作

这里有个更高级的输验证码的示例

其他

植入cookie

需要注意的是使用ngx.time()产生秒级的时间,用来做随机数种子可能会冲突,因此建议加上另外的随机变量(如下面的例子用的是客户端的ip) 可以使用ngx.now()产生毫秒精度时间