首页 > 程序资源 > Nginx 下 Typecho 正确设置 Url 重写,避免 “开启反垃圾保护” 后无法留言。

Nginx 下 Typecho 正确设置 Url 重写,避免 “开启反垃圾保护” 后无法留言。

博客有很久一段时间都没有 “开启反垃圾保护”,也不是我不想开,而是....

我特么开了以后,就无法留言了...而我又比较懒,所以就干脆把反垃圾关掉了,反正也没几个人评论。

不曾想,是啊,没人评论,垃圾评论机器人可真不少,每天都有一堆垃圾评论怼进来,删删删的翻了,我要看下到底是为啥反垃圾评论会吞评论...

找了一通,发现问题了...

打开页面时程序给的 “反垃圾 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);
});

所谓攻防,就是把破腚漏出来,还不怕被打,等着了~~~

上一篇: Linux下实现系统启动后每隔3天执行一次脚本。

下一篇: 一个(pomelo)网页游戏的数据包(黑箱)分析过程。

最近回复

标签