博客有很久一段时间都没有 “开启反垃圾保护”,也不是我不想开,而是....
我特么开了以后,就无法留言了...而我又比较懒,所以就干脆把反垃圾关掉了,反正也没几个人评论。
不曾想,是啊,没人评论,垃圾评论机器人可真不少,每天都有一堆垃圾评论怼进来,删删删的翻了,我要看下到底是为啥反垃圾评论会吞评论...
找了一通,发现问题了...
打开页面时程序给的 “反垃圾 Token” 和提交评论时程序再次生成的 “反垃圾 Token” 不一致。
具体影响代码在 /var/Widget/Security.php:115
:
/**
* 保护提交数据
*
*/
public function protect()
{
if ($this->_enabled && $this->request->get('_') != $this->getToken($this->request->getReferer())) {
$this->response->goBack();
}
}
这里要提一下 Typecho 的反垃圾逻辑:
我们认为垃圾评论发送者一般是在网上不断地爬网站,然后尝试填充页面的 form 并提交。
而 Typecho 反垃圾的逻辑就是,爬虫不会执行 JS 代码,那么我把表单的一个元素用 JS 来生成,后台只要检查提交的评论里面有没有这个 JS 生成的值即可。
而这个 JS 生成的值就是 md5(secret + PageUrl)
,然后由 JS 将值插入 form 中的隐藏 input[name="_"]
中。
这个逻辑是没问题的,而且我认为简单有效,非常好使,并且不能评论的问题也不在这里。
问题出在了一个想不到的地方,就是计算 md5 时使用的 PageUrl 这里,
检查 /var/Widget/Security.php:83
的调用者,
一个是上面发的检查 /var/Widget/Security.php:115
,
还有一个地方是打开页面是输出 JS 的地方 /var/Widget/Archive.php:1812
两个地方分别使用不同的方法提交了地址:
$this->request->getRequestUrl()
&& $this->request->getReferer()
打开页面时获取的是当前页面的(路由)地址,而提交评论时使用的是来路(Referer),这两个地方不一样...
坑的地方就在于,我 Nginx 里面的配置是:
if (!-e $request_filename) {
rewrite ^/(.*) /index.php?$1 last;
}
这就导致 getRequestUrl()
获取的地址是 "https://www.qs5.org/Post/687.html?Post/687.html",而 Referer 则是 "https://www.qs5.org/Post/687.html";
血的教训啊,自己小小的傻逼了一下,导致整个功能就废了...
修改 Nginx 配置就可以了,这也是 Typecho 正确的 Nginx 静态重写配置:
if (!-e $request_filename) {
rewrite ^/ /index.php last;
}
另外研究了一下 Typecho 前端混淆 Token 的 JS,做了一下还原,我要看下写爬虫的菜菜们什么时候来抄这段代码...
或者,菜菜们能看懂这段代码么?因为我用 JS 写的,如果看不懂,那除非用 JS 写的爬虫,不然没法用,可是用 JS 写的又可以直接 eval 代码,怎么都是多此一举。
用其他语言的话,就必须看懂才知道怎么转换成自己的语言的写法。
$.get(location.href).done(function (html) {
let info = html.match(/input\.name\s*=\s*'_';[^{]+{[^=]+=\s+([^,]+),\s[^=]+=\s*([^;]+);/),
hash = info['1'].replace(/\/(\*[^*]*\*\/|\/[^\n]*\n?)/g, '')
.replace(/'([^']*)'\+?/g, '$1'),
map = info[2].matchAll(/\[([^\[\]]+)\]/g),
item = map.next();
while (!item.done) {
let items = item.value[1].split(',');
hash = hash.substring(0, items[0]) + hash.substring(items[1]);
item = map.next();
}
console.log(hash);
});
所谓攻防,就是把破腚漏出来,还不怕被打,等着了~~~
换链接 啥也不说。我就看看
受教了,本来是打算利用评论做一个说说页面,通过评论接口模拟POST请求提交的,一直失败,检索发现这篇文章才知道是因为开启了反垃圾保护的缘故....