写在前

说来你们可能不信,昨天一个乙方系统的同学发了这么个需求来找我帮忙配……What?!😱😱😱

对于上述需求不予评价,但就这个事来说我觉得我有必要整理下Nginx相关配置的东西了……一是防止自己闹出这种笑话;二也是因为岁数大了记性差了,还是写点东西备查吧。

从一堆timeout说起

proxy_connect_timeout

Syntax: proxy_connect_timeout time;
Default: proxy_connect_timeout 60s;
Context: http, server, location
官方文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_connect_timeout

这个参数定义的是Nginx与后端服务器(“proxied server”,被代理的服务器)建立连接的超时时间,一般不应大于75s。

proxy_read_timeout

Syntax: proxy_read_timeout time;
Default: proxy_read_timeout 60s;
Context: http, server, location
官方文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_read_timeout

这个参数定义的是Nginx读后端服务器(“proxied server”,被代理的服务器)响应包的超时时间(需要注意的是这个时间指的是两次成功读取造作的间隔时间而不是读取完整响应包的总时间)。超过这个时间没有收到后端服务器传送数据的话连接就会超时断开。

PS:该值过小可能会导致504的情况出现,如不想遇到可以将此值改为略大于后端服务器响应超时的时间。

proxy_send_timeout

Syntax: proxy_send_timeout time;
Default: proxy_send_timeout 60s;
Context: http, server, location
官方文档:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_send_timeout

这个参数定义的是Nginx给后端服务器(“proxied server”,被代理的服务器)发送请求包的超时时间(需要注意的是这个时间指的是两次成功写取造作的间隔时间而不是发送完整请求包的总时间)。超过这个时间没有发送数据给后端服务器的话连接就会超时断开。

(未完待续)

 

点击数:582

最近在做的两个功能都需要对request body进行读取处理,好在OpenResty提供了相关函数,这里简单记一下。

获取request body

ngx.req.get_body_data

官方文档:https://github.com/openresty/lua-nginx-module#ngxreqget_body_data

简单说这个函数是获取内存中request body。获取成功时它会返回string类型的request body(如果需要table形式的请求参数可以使用ngx.req.get_post_args()函数);获取失败时返回nil,返回nil可能是以下原因造成的:

  1. request body没有被读入;
  2. request body已被写入临时文件(temporary file);
  3. 没有request body(request body大小为0)。

因为Nginx默认不会读取request body,所以为保证可以如期的获取到,我们最好先请求ngx.req.read_body()函数(或者打开lua_need_request_body开关强制读取request body。PS:不建议这样做),再去请求ngx.req.get_body_data();当request body已被写入临时文件时,我们需要通过ngx.req.get_body_file()函数来获取request body。

ngx.req.get_body_file

官方文档:https://github.com/openresty/lua-nginx-module#ngxreqget_body_file

这个函数和上面ngx.req.get_body_data相似,但是是用来获取临时文件中request body的。当还没有读取request body或request body在内存中时会返回nil。

这里需要注意的一件事是这时读出来的数据是只读的,不可以再在Lua代码中进行手工的modified、rename、remote。

Nginx的几个重要配置

讲到这里,感觉前面好像错过了什么重要的细节……对,就是request body到底在哪里?什么时候在内存,什么时候在临时文件?说到这个就需要去翻一下Nginx的文档啦~

client_max_body_size

首先先来看下client_max_body_size,这个参数设置了被允许的最大的request body大小,当一个request超过这个值的时候将会返回413错误(Request Entity Too Large)。如果不需要检查request body的大小将此值置为0即可。

client_body_buffer_size

再来看下client_body_buffer_size,这个参数设置了读取request body的buffer大小(默认值是两个内存页的大小,8k|16k)。当request body大于这个值时就会写在临时文件中。

好了,前面的疑惑解决了,但是还有两个问题:如何让request body只在内存或者临时文件中呢?

强制使用内存存request body

前面讲了client_max_body_size和client_body_buffer_size两个参数,其实将client_body_buffer_size设为client_max_body_size的大小就可以强制把request body放在内存中了。

强制使用临时文件存request body

Nginx配置中有个client_body_in_file_only参数(详见这里),开启后就强制把request body放在临时文件中了。

最后

好了,文章戛然而止,没有“最后”……

 

点击数:1111

我怎么知道我一个RD为什么要来研究这个,可能是因为身边的同学们都想把我当全栈培养吧……🤦‍♂️

背景

某台Nginx反代服务器(假定IP为10.10.1.2)在公司的某个新办公区网段(假定为172.16.0.0/16)怎么也访问不到,主机本身iptables没有限制,从该主机(10.10.1.2)ping不到172.16段的网关,traceroute时会跳到外网。经排查,172.16段到10.10.1.2的内网网关(假定为10.10.1.1)是通的,最终锁定到问题是因为10.10.1.2是双网卡的服务器,默认走的是外网网卡(假定为bind1,内网网卡是bind0)的网关(假定外网网关为123.123.123.1),到172.16.0.0/12段没有配置相应路由,所有需要在主机上单独配下。

查看路由表

修改路由之前还是先来看下当前我们的路由表是什么样子的吧

其中,第一列Destination是目的地址或目的网络;
第二列Gateway是网关地址,如果没有设置,这里是“*”;
第三列Genmask是目的网路的掩码,如果目的地址是主机时这里是“255.255.255.255”,默认路由这里是“0.0.0.0”;
第四列Flags路由标志:“U”表示该路由是启用状态,“G”表示使用网关……
第八列Iface是这条路由的数据包将发给的网卡。

所以这里可以看到默认是指到了外网网关123.123.123.1上,到10及192.168段的也有单独配指到内网网关10.10.1.1的路由,但是到172.16.0.0/12段的没有单独的路由,所以当traceroute 172.16.0.0/12段IP时会从外网网关进外网也就可以理解了。

添加路由

那么现在我们把去172.16.0.0/12段的下一跳指到内网的网关(10.10.1.1)上应该就可以了。

其中,“-net 172.16.0.0 netmask 255.240.0.0”表示目的网段;
“gw 10.10.1.1”指定了将使用10.10.1.1这个网关;
“dev bond0”指定了bond0这个网卡。

配完以后再检查一下路由表,已经有了刚才的配置,traceroute 172.16段的网关下一跳也到了内网网关,网路也通了。

删除路由

一个小插曲,刚才在添加路由时手滑把172.16.0.0/12的掩码写成了255.255.240.0所以导致加出了一跳错误的配置,这时可以通过route del 来删除路由:

最后

好了,问题解决了,其他上面没涉及细节以后遇到再来补吧~

最后再次感谢身边同学们对我的栽培……🤦‍♂️

 

点击数:273

来到甲方做安全后也算是亲眼见识了现在流量劫持到底有多厉害,周末闲着没事突发奇想还是把自己的博客也升到HTTPS吧,虽然其实真没有什么需要保护的东西……😂

这里简记一下过程,希望对需要的同学能有帮助~

证书购买

上HTTPS首先需要一个SSL证书啦,SSL证书分为3类:

DV:最低级别认证,可以确认申请人拥有这个域名。对于这种证书,浏览器会在地址栏显示一把锁。
OV:确认域名所有人是哪一家公司,证书里面会包含公司信息。
EV:最高级别的认证,浏览器地址栏会显示公司名。

对于个人博客一个DV证书就够用了,所以我在阿里云上买了一个Symantec的免费DV证书(PS:如果需要买更高级的付费证书的话欢迎先来这里领张优惠券来~)。买完之后去“控制台-安全(云盾)-证书服务”里完善一下相应信息,稍等一下审核完毕就可以用啦~

配置Nginx

有了证书下面就要在Nginx里配上了啦~

首先下载证书及私钥文件放到Nginx目录的cert目录(没有的话建一个)中,然后修改Nginx配置:

reload Nginx即可通过https访问了~测试没问题后就可以将http的配置下掉了,这里可以将http的请求301重定向到https:

reload Nginx即可。

更新WordPress设置

下面还需要更新下WordPress的设置,将后台“设置-常规”中的“WordPress地址(URL)”和“站点地址(URL)”改为HTTPS的地址。

解决残留的http链接

由于博客已有的文章中可能包含原来的http链接(如图片等)这可能会导致浏览器认为网站的部分页面不可信,所以我们需要将所有文章中的http链接改成https。如果文章太多了可以直接去数据库中批量替换,虽然直接动数据库不是个好习惯(记得提前备份哦):

好了,一切搞定,静静地欣赏https上的那把绿色小锁头吧~

点击数:4057

写在前

如何黑掉一个验证码?很多人第一反应是验证码识别,什么预处理,提取有效信息,分割字符,识别字符,吧啦啦一长串流程……其实有时根本没那么复杂,今天就来讨论些除了验证码识别还可以怎么黑掉一个验证码。

论如何黑掉验证码

使用cookie/session记录登录失败信息
很多时候为了用户体验验证码只有在登录失败一定次数后才会弹出验证码,但是当登录失败次数被记录在cookie或session时,如果攻击者不使用cookie或每次使用新的session验证码弹出机制将被绕过。

验证码使用后不过期
通常验证码与session存在对应关系,当一个验证码验证成功后未做过期处理,攻击者则可反复使用这组验证码和session;当一个验证码验证失败后未做过期处理,则可能会被暴力破解。

验证码使用后过期处理不及时/过期机制可被绕过
如果验证码更新不及时或更新机制可以被绕过将导致攻击者仍旧可以使用用过的验证码。

将验证码的值返回客户端
将验证码的值通过response、cookie等方式返回给客户端将会使验证码失去存在的意义,即使使用md5等方式返回也同样存在这种风险。

验证码可预测
如可根据验证码生产算法预测出验证码的值。

验证码的值域太小
如果验证码的值只有10个,那么攻击者随便尝试一个就有10%的正确率。

无超时/超时时间过长
验证码无超时或超时时间过长可能会给人工打码提供机会,如先收集验证码及对应的session,然后进行人工识别,在需要时再取出人工识别过的验证码和对应的session使用。

绕过验证码
这个属于系统整体设计的问题,如一个功能在PC端有验证码而移动端没有的话,攻击者完全可以利用移动端的接口去实现攻击而没必要再去黑掉验证码。

验证码易识别
想想最后还是不得不讲回验证码识别,一个过于简单的验证码确实还是无法达到防御的目的地。

最后

有些话等过两天再来讲吧……

点击数:626

之前在WooYun知识库上写过一篇《初探验证码识别》,主要介绍了一些基本的验证码识别过程,并且给出了一些设计(改进)验证码时值得考虑的地方。正好最近没事在写Python Web玩时注册、登录等操作需要用到验证码,那么就借着这个机会自己写一个吧~

验证码

“验证码”又名“全自动区分计算机和人类的图灵测试”(英语:Completely Automated Public Turing test to tell Computers and Humans Apart,简称CAPTCHA),最早在2002年由卡内基梅隆大学的路易斯·冯·安、Manuel Blum、Nicholas J.Hopper以及IBM的John Langford所提出,是一种区分用户是计算机或人类的公共全自动程序。

利用其区可分人或计算机的特点,在Web应用中,验证码常被用于注册、登录、发布信息等处,以避免计算机程序恶意进行批量注册、暴力破解用户密码、发布大量打击信息等。

验证码的设计与实现

生成一个简单的验证码

首先,我们使用PIL (Python Imaging Library) 这个库来生成一张验证码图片。这里我们随机选择了4个字符并绘制了一张120*40的白色背景图,然后在相应位置绘制了指定字体和字号的字符。

利用上面的代码便可生成一个简单的验证码了。

5sge

但是从这个验证码字符分隔明显、前背景易区分且无其他干扰,所以它还是比较容易被识别的。因此我们需要在此基础上进一步加工这个验证码。

添加干扰

我们可以在验证码上绘制一些干扰线,ImageDraw.Draw对象的line函数可以很方便的在我们输入的两个点间绘制一条直线:

除了干扰线外我们还可以绘制一些干扰点,因试验发现干扰点较小很容易被降噪处理去掉,而较大又影响验证码的直观体验,所以这里采用了一些较小的字符来对验证码进行干扰:

这里以千分比的方式来控制干扰的强度。

随机字符位置

如果每个字符的位置固定的话,可以很容易的通过位置分隔开每个字符,所以字符位置最好是随机的。另外,通过投影或者连通区域的方法分隔字符的时候可以比较容易的将两个不粘连的字符分开,所以这里在随机范围的设定时,允许存在1/3的字符粘连:

颜色设置

在去干扰时,如果颜色上存在字符和干扰(线、字符等)的分界点的话那么所有干扰就失去了意义,所以在颜色设置方面要尽量使其存在交集,在不影响直观感受的情况下,交集越大越不容易被识别。

其他考虑

字符选择

因部分字体在没有相应辅助信息(如:对齐、拼写环境等)的条件下类似于:1、I、l,0、o、O,2、z、Z这类字符不易辨别,所以在设计验证码时一般会去掉此类字符以降低用户识别难度。

代码

完整代码如下:

 

点击数:6395

安装Supervisor

生成默认配置文件

生成默认配置文件的方法如下:


配置文件常用配置如下:


启动Supervisor

通过如下命令使用上述配置文件启动Supervisor:

管理Supervisor中的进程

通过supervisorctl可以对Supervisor启动的进程进行管理,首先使用下面的命令打开Supervisor的控制台:

相关命令如下:

注:programxxx[program:theprogramname]里配置的值。

另外,通过Web端也可以进行管理,地址及认证信息详见[inet_http_server]中的配置。

点击数:1200

写在前

最近在写一个模拟登陆腾讯企业邮箱的东西,但是发现在POST的数据中有一个p字段的内容是一个加密的字符串。经过查看源码发现p字段的值原来是由表单中pp和ts两个字段的值拼接并进行RSA加密的结果经过base64编码后得来的,其中pp字段是用户输入的密码,而ts字段是一个时间戳(在页面源码中已经给出)。最初的想法比较偷懒,想去直接调JS代码算出个结果返回回来,但是发现调这个JS太麻烦了,还不如直接用Python代码重新实现一遍这个加密算法呢……于是乎,折腾起来吧~

关于p值的来历

实现

首先,获取RSA算法的公钥和ts值很简单,直接从页面源码中按字符串处理的方式即可提取出公钥(当然,这里上个正则秀个操作也是可以的~),而ts的值从form表单中即可获取。

 

RSA算法的实现可以直接使用第三方库rsa,将加密后结果(十六进制)做base64编码即为所求的p值。

 

如果有细心的人验证结果是否正确时可能会发现我们算出来的p值和抓包抓到的提交的p值完全不同,但是不要慌,因为RSA算法在进行加密时会进行一个随机填充(而不是填充固定值,如全0),所以由于填充的值不同,我们算出来的结果与抓包看到的p值不同是正常的,不影响正常登录。

在提交完登录表单后会得到一个“重定向”的页面,这个页面里就包含了登陆进邮箱的地址targetUrl,并通过window.location.replace的方法将窗口“重定向”到了targetUrl。

登录成功后的返回结果

好了,任务完成~

前端加密在安全上的用途

了解安全的人都知道,明文传输登录表单是件很不安全的事情,因为我们无法保证数据在传输过程中的安全性,如果表单内容被嗅探,攻击者便可轻松直接拿到我们的帐号密码。对于这个问题一个比较好的解决办法就是启用HTTPS,使用HTTPS的安全性固然很高,但是由于其在经济、性能等方面都需要花费较大的成本,所以这种方案的应用并不十分普遍,而前端加密则是一种比较常见的替代方案,它通过前端JS对敏感数据加密然后再进行传输,可以很大程度上的减少资源的消耗。

下面以登录为例,我们来看一下通过前端加密传输密码的过程。

首先在我们请求登录页面的时候,服务器会将一个公钥(PublicKey)和一段用于加密的JS代码一起发给用户,在提交表单时浏览器会先执行这段JS代码对密码进行加密,然后将加密后的密码密文连通表单其他数据一起提交到服务器。这样数据包即使在传输过程中被嗅探到,但是由于没有私钥,攻击者仍然无法拿到真正的密码。

在此基础上,为了防止重放攻击等问题,服务器通常还会在用户请求登录页面的时候给用户发送一个盐值(salt),JS在进行加密时会将盐值和密码的明文一起加密。这样,由于每次的盐值不同所以每次加密后的密文也会不同,这样可以有效的避免重放攻击。

对于上面所提到的“用于加密的JS代码”的加密算要求是公钥加密算法,这样可以有效的防止攻击者解出密码的明文,一般多为RSA算法。

最后

虽然前端通过JS加密表单敏感数据的方法新浪微博、人人网等一些网站都在使用,但是目前网上关于这种方案的相关介绍还不是很多,所以如果您有这方面的资料或者经验可以分享的欢迎随时Email我,非常感激~

点击数:4440