virusdefender 发布的文章

Django 生成的数据库表 id 字段溢出问题

某个系统,突然数据库插不进去数据,报错如下

[2017-04-22 23:17:55] - [ERROR] - [utils.api.api:146]  - integer out of range
Traceback (most recent call last):
  File "/usr/local/lib/python3.5/dist-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
psycopg2.DataError: integer out of range

然后表结构是这样的

user=# select * from acl_ip_data_id_seq;
   sequence_name    | last_value | start_value | increment_by |      max_value      | min_value | cache_value | log_cnt | is_cycled | is_called 
--------------------+------------+-------------+--------------+---------------------+-----------+-------------+---------+-----------+-----------
 acl_ip_data_id_seq | 2147550630 |           1 |            1 | 9223372036854775807 |         1 |           1 |       7 | f         | t
(1 row)

看到21亿这个数字很熟悉,是 int 最大值,怀疑是数据库 id 字段达到了最大值,无法继续增长了。

这个表是 Django ORM 生成的,看了下 migration,这个字段是AutoField,发现其实就是IntegerField

https://docs.djangoproject.com/en/1.9/ref/models/fields/#autofield

但是只有 Django 1.10 才支持更大的整形 ID 字段

https://docs.djangoproject.com/en/1.10/ref/models/fields/#bigautofield

前几天刚看了饿了么的技术一个故障分析,是一样的原因 http://efs.ele.me/?p=246 结果过了几天就遇见了。

前端MVVM框架可能出现的安全问题

这些年,AngularJS、React 和 Vue.js 算是前端框架中比较热门的,相对于 jQuery 等框架,有一些不太一样的可能出现问题的点,当然都是集中在 XSS 上。

模板注入

类似后端模板注入,前端模板注入也是存在的,被分析最多的还是 AngularJS,详见 https://docs.angularjs.org/guide/security

  • 后端直接生成前端模板,比如{{1+1}},然后AngularJS 去解析和执行。
  • 部分表达式和表达式 parser 的参数可以被控制,比如$watch(userContent, ...) $compile(userContent)

之前的 AngularJS 是有个沙箱的,隔离了部分 runtime context,但是最新版本中去除了,因为多次的被绕过,而且并没有真正的提升安全性。

在其他框架中也是存在类似的问题的、

直接插入 HTML

MVVM框架一般不需要关心 dom 操作,但是有时候还必须手动的插入和控制一些 HTML,框架也是提供了相关的方法的。

  • Vue.js 的{{{ data }}}v-html
  • AngularJS 的$sce.trustAsHtml
  • React 的dangerouslySetInnerHTML

这时候就应该认真检查用户输入的数据了。

我感觉 AngularJS 和 React 的函数名字设计的特别科学,你要知道 trust 那些 dangerous 的数据才可以,还比如 grpc 中,使用非 SSL 的时候,方法名是add_insecure_port

SSR

为了解决 SPA 页面的 SEO 问题的,主流框架也提供了 SSR 方案,但是 SSR 的时候就经常的忘记了转义和过滤,一个是说程序员的问题,使用了危险的函数,另外一个就是框架的漏洞了。

比如新版知乎页面使用了 SSR,会先把用户的问题输出到页面上,然后后续再执行 JS 做进一步的动作,然后估计是使用了dangerouslySetInnerHTML,导致用户问题中的 JS 被执行,导致了XSS。

请输入图片描述

Vue.js 在 SSR 的时候,默认会转义用户输入,但是在样式中忘记处理了,导致了 XSS。见下面的 demo

var Vue = require('vue')
var app = new Vue({
  data () {
    return {
        xss: '"><script>alert(1)</script>'
    }
  },
  render: function (h) {
    return h('a', {style: {color: this.xss}}, 'foo')
  }
})
var renderer = require('vue-server-renderer').createRenderer()
renderer.renderToString(app, function (error, html) {
  if (error) throw error
  console.log(html)
})

英语流利说-懂你英语使用感受

一个偶然的机会接触到了英语流利说,很惊喜,可以通过自动化的语音识别来标注发音情况。

根据一些资料,英语流利说是使用了离线的神经网络语音识别,因为已知正确的文本和发音,只需要将用户的发音尽量和已知文本上对齐就好了,也就是GOP算法。

英语流利说课程分两大部分,一个是独立的小课程,比如"排名前十的旅行问题"、"不做学霸做面霸",每个课程分为几十个关卡,每个关卡讲一个小问题,大约10分钟之内就可以搞定一个。另一部分就是懂你英语了,也是本文重点说的。

开始购买了一个月的懂你英语,之后购买了半年。价格是单月购买99元,半年499元。因为是机器语音识别,感觉利润率还是挺高的。

在课程结束的时候,如果你的学习效率和平均得分达到90,总计学习时间达到90小时,是可以全额退还学费的。我一开始学习的时候,学习效率是60,目前已经达到了80多。平均得分倒一直是90多分左右,两个月内学习时间是57个小时。

IMG_1945.PNG

优点

  • 比免费的课程要质量高一些,更系统一些。
  • 有一个学习群,有班主任,每天提出一个话题来讨论,同时公布前一天大家的学习情况,有竞争的感觉。而且有时候会有活动,比如三个人连续三天都学习超过半小时,可以延长课程时间或者赠送付费课程等。
  • 卡片式任务,已经有不少app使用这种设计了,将一个整体划分为系统性的小任务,每天都会有清晰的目标。一个Level一般包括4个Unit,每个Unit包括4个卡片,每个卡片上有6个Lesson。包括Listening,Vocabulary,Dialogue,Reading,Matching, Grammar,Speaking,Dictation等类型。基本上一个Lesson认真的学习要花费一个小时左右的时间(部分练习性质的除外),包括逐句的录音和完成Lesson中的题目。

IMG_1180.PNG

  • 打卡,数据统计等对于安排学习和了解学习效果很有帮助。
  • 确实有"沉浸式的英语学习体验"
  • 难度控制的不错,我从Level 3开始学的,现在在准备Level 4的考试。通过考试才能进入下一个Level。总体来说,难度有所增加,但是变化很平缓。

- 阅读剩余部分 -

Python 模板字符串与模板注入

这几年比较火的一个漏洞就是jinjia2之类的模板引擎的注入,通过注入模板引擎的一些特定的指令格式,比如{{1+1}}而返回了2得知漏洞存在。实际类似的问题在Python原生字符串中就存在,尤其是Python 3.6新增f字符串后,虽然利用还不明确,但是应该引起注意。

最原始的%

userdata = {"user" : "jdoe", "password" : "secret" }
passwd  = raw_input("Password: ")

if passwd != userdata["password"]:
    print ("Password " + passwd + " is wrong for user %(user)s") % userdata

如果用户输入%(password)s那就可以获取用户的真实密码了。

format方法相关

https://docs.python.org/3/library/functions.html#format

除了上面的payload改写为print ("Password " + passwd + " is wrong for user {user}").format(**userdata)之外,还可以

>>> import os
>>> '{0.system}'.format(os)
'<built-in function system>'

会先把0替换为format中的参数,然后继续获取相关的属性。

但是貌似只能获取属性,不能执行方法?但是也可以获取一些敏感信息了。

例子: http://lucumr.pocoo.org/2016/12/29/careful-with-str-format/

CONFIG = {
    'SECRET_KEY': 'super secret key'
}

class Event(object):
    def __init__(self, id, level, message):
        self.id = id
        self.level = level
        self.message = message

def format_event(format_string, event):
    return format_string.format(event=event)

如果format_string{event.__init__.__globals__[CONFIG][SECRET_KEY]}就可以泄露敏感信息。

理论上,可以通过类的各种继承关系找到想要的信息,比如在Django中的思路为 https://xianzhi.aliyun.com/forum/read/615.html

Python 3.6中的f字符串

这个字符串非常厉害,和Javascript ES6中的模板字符串类似,有了获取当前context下变量的能力。

https://docs.python.org/3/reference/lexical_analysis.html#f-strings

>>> a = "Hello"
>>> b = f"{a} World"
>>> b
'Hello World'

而且不仅仅限制为属性了,代码可以执行了。

>>> import os
>>> f"{os.system('ls')}"
bin      etc      lib      media    proc     run      srv      tmp      var
dev      home     linuxrc  mnt      root     sbin     sys      usr
'0'

>>> f"{(lambda x: x - 10)(100)}"
'90'

但是貌似没有把一个普通字符串转换为f字符串的方法,也就是说用户很可能无法控制一个f字符串,可能无法利用,还需要继续查一下。