2019独角兽企业重金招聘Python工程师标准>>>

基于日志的统计分析按日志来源一般分为后端 cgi、app 日志和前端 js 挂码日志,其中前端 js 挂码由于与具体后端业务逻辑低耦合、异步加载等特性,使得其在网站统计分析领域应用广泛。

今天就来看一个 nginx 日志收集过程中的 case。

最近在 review nginx 配置的时候,发现 nginx 每天会有 1% 的 errlog,由于公司的业务访问量还算比较大的,算下来这 1% 也不是个小数目,有必要搞清楚这 1% 究竟怎么产生的。

1、错误日志样式:

错误日志的样式大致分为两种,如下:

2014/07/03 00:06:51 [error] 30605#0: *15901655967 client sent invalid userid cookie "cookieuid1=05dvUVObOC+UGCrSG4gWAg==; jobbest_cateid=38676; isfirst=true; showcountdown=true; stopnotice=true; _TCN=4FD2E673D11B18C5060BF413BB796EB5; idooxx="05dz8VO0Lew1TT66I0MUAg=="; ...2014/08/13 11:01:25 [error] 13702#0: *19402474334 open() "/opt/web/tracklog.ooxx.com.static/mooxx/m3/js/m.lazyload.js" failed (2: No such file or directory), client: 42.249.142.200, server: tracklog.ooxx.com, ...

前者在整个 errlog 中占比 99%,后者 1% 左右,前者就是今天要讨论的主题:为什么 nginx 会报这种错误,而后者这种错误一般是原本的访问路径不正确或者运营商劫持导致访问路径错误。

2、按图索骥:track nginx source code

搜了下,网上貌似很少有人问到这个问题,即使问到了也貌似没有明确的解答,当 STFW 和 RTFM 都不管用的时候,那就只有硬着头皮看源码了,按图索骥,看看源码中,何处抛出的 client sent invalid userid cookie 这个错误:

static ngx_http_userid_ctx_t *
ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
{
...ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,"uid cookie: \"%V\"", &ctx->cookie);if (ctx->cookie.len < 22) {cookies = r->headers_in.cookies.elts;ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,"client sent too short userid cookie \"%V\"",&cookies[n]->value);return ctx;}src = ctx->cookie;/** we have to limit the encoded string to 22 characters because*  1) cookie may be marked by "userid_mark",*  2) and there are already the millions cookies with a garbage*     instead of the correct base64 trail "=="*/src.len = 22;dst.data = (u_char *) ctx->uid_got;if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {cookies = r->headers_in.cookies.elts;ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,"client sent invalid userid cookie \"%V\"",&cookies[n]->value);return ctx;}...
}ngx_int_t
ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src)
{static u_char   basis64[] = {77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 62, 77, 77, 77, 63,52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 77, 77, 77, 77, 77, 77,77,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 77, 77, 77, 77, 77,77, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77,77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77, 77};return ngx_decode_base64_internal(dst, src, basis64);
}static ngx_int_t
ngx_decode_base64_internal(ngx_str_t *dst, ngx_str_t *src, const u_char *basis)
{
...for (len = 0; len < src->len; len++) {if (src->data[len] == '=') {break;}if (basis[src->data[len]] == 77) {return NGX_ERROR;}}if (len % 4 == 1) {return NGX_ERROR;}s = src->data;d = dst->data;while (len > 3) {*d++ = (u_char) (basis[s[0]] << 2 | basis[s[1]] >> 4);*d++ = (u_char) (basis[s[1]] << 4 | basis[s[2]] >> 2);*d++ = (u_char) (basis[s[2]] << 6 | basis[s[3]]);s += 4;len -= 4;}...return NGX_OK;
}

可以看到,源码中会对传入的 cookieId 做 base64 合法性校验,如果没有通过校验,则会抛出 client sent invalid userid cookie 错误,并按 HttpUseridModule 的逻辑重新分配新的 cookieId。

3、测试验证

为了证明上述推断的正确性,并解决上述的错误,我们只需要找出没通过校验的地方,并构造测试用例验证即可。

我们取一条正常的请求中的 cookie:

idooxx=05dvZ1ODTpI+FjiILHYwAg==; __ag_cm_=1408028234222; __utma=253535702.161ooxx51834.1401114262.1408099300.1408187334.7; __utmz=253535702.1401114262.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); _bu=201104111325386d88c794; city=bj; ooxxhome=bj; myfeet_tooltip=end; new_session=1; init_refer=; ipcity=bj%7C%u5317%u4EAC; __utmb=253535702.3.9.1408187335363; __utmc=253535702

用上述正确的对比错误的 cookie,可以看到,cookieId(idooxx) 中包含了双引号,而导致 cookieId 没有通过 base64 合法性校验的可能正是包含了 非 base64 编码字符串。下面我们来验证下,手动在浏览器中构造一个不合法 cookie,看看是不是有同样的问题。

由于 base64 编码只包含 64 个字符:大小写52 + 数字10 + 2个额外字符+/  一共64个字符。如果我们客户端发送的 cookieId 中包含了上述非 64 字符集中的字符,那么 nginx HttpUseridModule 模块就会校验后认为请求非法,并会重新非配 cookieId。

4、解决方案

原因找到了,要解决起来就不难了,其实分析这些错误有个共性,就是这些错误都是由移动端产生的,pc 端基本没有,因为 pc 端的浏览器请求的参数都是规范的,而移动端的很多都是 RD 自己拼接然后发送的,难免会不符合规范,有则改之。

5、Refer:

[1] nginx-1.7.3/src/http/modules/ngx_http_userid_filter_module.c

http://lxr.nginx.org/source/src/http/modules/ngx_http_userid_filter_module.c

[2] nginx-1.7.3/src/core/ngx_string.c

http://lxr.nginx.org/source/src/core/ngx_string.c

[3] Errors using HttpUseridModule

http://www.serverphorums.com/read.php?5,856195

[4] Base64编码/解码器

http://base64.xpcha.com/

[5] ngx_http_userid_module模块基本指令整理

http://www.iigrowing.cn/ngx-http-userid-module-mo-kuai-ji-ben-zhi-ling-zheng-li.html

转载于:https://my.oschina.net/leejun2005/blog/302443

Nginx log error:client sent invalid userid cookie相关推荐

  1. nginx报错:nginx: [alert] could not open error log file: open() “/var/log/nginx/error.log“ failed (2: N

    参考文章1:nginx error_log 错误日志配置说明 如图,启动nginx时报错: [root@RV1126_RV1109:/usr/sbin]# nginx -c /etc/nginx/ng ...

  2. nginx的error.log日志常见的几个错误解决方法

    nginx.conf里会有两个日志,分为access.log 和 error.log.其中这两个日志可以细化,一般来说在nginx目录下会有一个logs会保存,然后也可以在对应的server目录里可以 ...

  3. 小程序 U你caughtSyntax Error: Invalid or Unexpected token: 1: 2154

    一个耗费了我半天时间调试的问题,却是因为最简单的字符编码引起的,先做下记录,期间百度了很多,都没有解决我的问题,只好一步一步排查了. 做了个小程序,第一版本很正常,第二天我有上了新功能,就不正常了,数 ...

  4. 回归分析评估指标均方对数误差(MSLE)详解及其意义:Mean Squared Log Error

    回归分析评估指标均方对数误差(MSLE)详解及其意义:Mean Squared Log Error 目录 回归分析评估指标均方对数误差(MSLE)详解及其意义:Mean Squared Log Err ...

  5. 启动 nginx 时报错:error while loading shared libraries:

    Nginx 启动出错 error while loading shared libraries: libpcre.so.1 error while loading shared libraries: ...

  6. 成功解决Error:invalid character in identifier

    成功解决Error:invalid character in identifier 目录 解决问题 解决思路 解决方法 解决问题 解决思路 错误:标识符中的字符无效 解决方法 将单引号改为双引号即可! ...

  7. Moodl:集成密码,消除错误phpCAS error: phpCAS::client(): type mismatched for parameter $se

    1. Generate Moodle password For generating a moodle password , first of all include the the configur ...

  8. pycharm报错:Error configuring SDK: Accessing invalid virtual file: 解决办法

    pycharm报错:Error configuring SDK: Accessing invalid virtual file: 解决办法: 针对linux系统, 删除home目录下pycharm配置 ...

  9. 异常:Fatal error loading the DB: Invalid argument. Exiting

    异常:Fatal error loading the DB: Invalid argument. Exiting docker启动redis:docker start redis ,查看日志 :doc ...

最新文章

  1. linux shell 数组元素带空格,在bash中解析带有空格的JSON数组
  2. Android Hacks:在代码中隐藏软键盘
  3. 后台返回的数据换行显示
  4. 通过ObjectMapper将实体转成字符串 ,将 用json存的的list 回转list
  5. 服务器mvc提示404错误信息,解决Spring MVC提示404错误找不到JSP问题
  6. Mysql数据库(八)——mysql高阶语句(中)
  7. Hadoop实战项目之网站数据点击流分析(转载分析)
  8. 正则过滤符号_多角度理解正则项
  9. Linux操作系统中vi常见用法和相关配置
  10. Java集合框架介绍
  11. 从远程服务器中下载文件到本地
  12. Linux环境MySQL卸载教程
  13. linux中的段定义的,Linux中的段
  14. 关于nomogram核心函数的time.inc函数的设定
  15. 视频CMS是什么?你为什么需要它?
  16. 在你的应用里使用Jetty嵌入式
  17. Linux下chrony授时监测脚本
  18. 第001天:第一行Android代码
  19. cms 和 g1的主要区别
  20. 【零基础】看懂理解傅里叶变换后的频谱图-附例题

热门文章

  1. python26.dll没有发现_python26.dll 文件下载
  2. 深入理解ROS技术 【3】ROS下的模块详解(129-180)
  3. element-ui 表格table,动态显示每一列的,重置全选
  4. JavaScript严格模式 use strict
  5. mysql打印语句_大数据挖掘—(八):scrapy爬取数据保存到MySql数据库
  6. ATOM插件库,收藏以备不时仔细!
  7. php files上传错误,php-PHP上传文件的问题$_FILES['file']['error']
  8. 数据结构实验之图论八:欧拉回路
  9. 往有序链表的插入元素使原链表依旧有序
  10. Vue.js 服务端渲染