0x00 NoSQL 基础
什么是 NoSQL 数据库?
-
NoSQL(NoSQL= Not Only SQL),意即“不仅仅是 SQL",泛指非关系型的数据库 。
-
随着互联网 web2.0 网站的兴起,传统的关系数据库在应付 web2.0 网站,特别是超大规模和高并发的 SNS 类型的 web2.0 纯动态网站已经显得力不从心,暴露了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL 数据库的产生就是为了解决大规模数据集合多重数据种类 带来的挑战,尤其是大数据应用难题,包括超大规模数据的存储。
为什么要用 NoSQL?
-
随着互联网的不断发展, 各类型的应用层出不穷,在这个云计算的时代,对技术提出了更多的需求,主要体现在这四个方面:
-
低延迟的读写速度 :应用快速的反应能极大地提升用户的满意度
-
海量的数据和流量 :对于搜索这样大型应用而言,需要利用 PB 级别的数据和能应对百万级的流量
-
大规模集群的管理 :分布式应用能更简单的部罟和管理
-
庞大运营成本的考量 :在硬件成本、软件成本和人力成本能够有大幅度地降低
-
举例:例如谷歌或 Facebook 每天为他们的用户收集万亿比特的数据。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展
NoSQL 与 SQL 的区别
SQL 数据库 | NOSQL 数据 |
|
---|---|---|
存储方式 | SQL 数据存在特定结构的 表 中 | 可以是 JSON 文档、哈希表或者其他方式,比较 灵活可拓展 |
表数据集合的数据的关系 | 定义好表和字段结构后才能添加数据 ,表结构可以在被定义之后更新,但是如果有比较大的结构变更的话就会变得比较复杂 | 数据可以 在任何时候任何地方添加 ,不需要先定义表 |
JOIN 查询 | 支持 JOIN 多表查询 | 暂未提供 类似 JOIN 的查询方式。大部 NOSQL 使用 非规范化的数据存储方式 存储数据 |
数据耦合性 | SQL 中不允许删除已经被使用的外部数据 | 可以随时删除任何数据 |
事务 | 提供事务 | 没有事务这个概念,每个数据集的操作都是原子级的 |
NoSQL 的代表数据库
- MongDB、Redis、Memcache
NoSQL 的应用
-
目前许多大型互联网项目都会选用 MySQL(或任何关系型数据库) + NoSQL 的组合方案
-
举例:
-
关系型数据库适合存储结构化数据 ,如用户的帐号、地址:
-
这些数据通常需要做结构化查询
-
这些数据的规模、增长的速度通常是可以预期的
-
事务性、一致性
-
-
NoSQL 适合存储非结构化数据 ,如文章、评论:
-
这些数据通常用于模糊处理 ,如全文搜索、机器学习
-
这些数据是海量的 ,而且增长的速度是难以预期的
-
根据数据的特点,NoSQL 数据库通常具有无限(至少接近)伸缩性
-
按 key 获取数据效率很高,但是对 join 或其他结构化査询的支持就比铰差
-
0x01 MongoDB 基础
MongoDB 介绍
-
MongoDB 是流行的 NoSQL 数据库,它是个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。默认端口号为 27017
-
MongoDB 的特点
-
MongoDB 和其他的数据库一样,都支持常见存储操作,但是它可以存储任何的数据,包括文件。
-
MongoDB 允许在服务端执行脚本,可以用 javascript 编写某个函数,直接在服务端执行,也可以把函数的定义存储在服务端,下次直接调用即可。
-
MongoDB 数据操作使用 JSON 形式的标记。
-
MongoDB 支持各种编程语言:RUBY,PYTHON,JAVA,C++,PHP,C#等多种语言。
-
MongoDB 使用 db 关键字代表当前数据库。
-
MongoDB 语句
MongoDB 数据类型
MongoDB 基本 操作
-
MongDB的启动
-
开启服务: sudo mongodb
-
登陆 mongodb数据库:mongodb --host 127.0.0.1
-
数据库的操作
-
查看所有的数据库:show dbs
-
切换数据库:use数据库名
-
查看集合: show collections
-
数据库的创建:use 数据库名。有值自动创建 。当use的时候,系统就会自动创建—个数据库。
-
删除数据库:进入数据库后db.dropDatabase();
-
-
注意:如果没有选择任何数据库,会删除默认的test数据库
-
集合的操作
-
查看集合:show collections
-
创建集合:db.createCollection("xxx")
-
删除集合:db.xxx.drop()
-
-
文档(行)的增删改
-
增加数据:db.xx.insert({key:value})
-
举例:db.chunqiu.insert({id:1,name:"web",age:10})
-
删除数据: db.xx.remove(删除的条件)
-
全部删除:db.xx.remove({})
-
根据条件删除,默认是删除所有符合条件的数据: db.xx.remove({age:10})
-
只删除符合条件的第一个: db.xx.remove({gender:true},{justOne:true})
-
更改操作:db.update({查找的条件},{修改的内容})
-
修改内容:默认其他原有字段删除了,替换掉原有数据:db.xx.update({age:10},{name:"NoSQL"})
-
保持原有的字段,加一个修饰$set:默认只修改第一个且对已存在的原有属性是替换,不存在的属性是添加
-
db.stu.update({age:10}, {$set:{like:"study"}})
说明:把like:"study"添加到数据里面,并不是换
-
文档查询简单语句:
-
基本查询:db.xx.find({查询条件})
-
查询所有的数据: db.xx.find() 或db.xx.find()
-
默认查出所有符合条件的数据:db.xx.find({age:10})
-
查找符合条件的第一个:db.xx.findOne({age:10})
-
格式化输出— pretty()函数:db.xx.find({age:10}).pretty()
-
-
常用条件
$lt | < |
---|---|
$lte | ≤ |
$gt | > |
$gte | ≥ |
$ne | ≠ |
$in | in |
$nin | not in |
$all | all |
$or | or |
$not | 反匹配(1.3.3及以上版本) |
$regex | 正则 |
-
条件查询:
-
举例:
-
db.xx.find({age:{$lt:20}}) 查询年龄小于20岁的
-
db.xx.find({age:{$ne:18}}) 查询年龄不等于18岁的
-
-
逻辑运算:$and , $or
-
$and:默认的的查询条件就是且的关系
-
举例:
-
db.xx.find({age:28,gender:true})
-
db.xx.find({$and :[age:28},{gender:true}]}) 查询年龄是28岁且性别为女
-
-
$or:或的关系
-
举例:
-
db.xx.find({$or :[age:{$lt:30},{gender:false}]}) 查询年龄小于30岁, 或者性别为男
-
0x02 NoSQL注入分类
- Web应用和服务通常使用 NoSQL数据库去保存客户数据。图为典型web应用架构。该程序自身可能不易受到攻击,但有时它们提供了不安全的API ,当应用开发人员错误地使用它们时就会给该应用引入漏洞,这些漏洞会被人利用对数据库进行
任意操作。
- NoSQL注入分为4种
-
重言式/永真式(重要)
-
JavaScript注λ(难度较大)
-
联合查询注入(被淘汰)
-
mongoshell拼接注入(难度中等,危害大)、
- 语言、代码逻辑角度分类(3种):
-
PHP数组注入
-
JS注入
-
Mongoshell拼接注入
- 攻击手段角度分类(3种)
-
重言式(永真式)
-
联合查询
-
Javascript注入
重言式注入
-
什么是重言式注入?
-
重言式又称为永真式。此类攻击是在条件语句中注入代码,使生成的表达式判定结果永远为真 ,从而绕过认证或访问机制使用 Mongo DB进行数据库查询的过程:
- MongoDB将查询语句存放在数组中,再将数组带入数据库进行查询。此过程安全性较高,不存在单引号闭合的问题。但是由于PHP的特性导致注入仍然存在。
- 解释:
就PHP本身的性质而言,由于其松散的数组特性,导致如果我们输λ value=1那么。也就是输入了一个 value的值为1的数据。如果输 value[$ne]=2,也就意味着value=array($ne=>2),在MongoDb得角度来,很有可能从原来的个单个目标的查询变成了条件查询
从 xxx.find({'key':'A'}) ====> xxx.find({'key':{$ne:'A'}})
- 防御:可以通过函数 is_array将输入参数转变字符串类型来解决
db->logins->find(array("username"=>(string)$_POST["username"],"password"=>(string)$_POST["password"]));
- 注意:
-
必须要结合PHP语言才能导致重言式注入(依据PHP语言的特性),ASP没有永真式注入
-
如果是POST方法传参,可以结合 Burp Suite抓包、改包进行绕过。
-
使用正则表达式也可以构造永真式如:
username[$regex]=.*?&password[$regex]=.*? # .*?为匹配所有字符串
JavaScript注入
-
什么是 JavaScript注入?
-
这是一种新的漏洞由允许执行数据内容中 JavaScript 的 NOSQL数据库引入的。 JavaScript使在数据引擎进行复杂事务和查询成为可能。传递不干净的用广输入到这些查询中可以注入任意 JavaScript代码这会导致非法的数据获取或篡改
-
注入产生的原因
-
MongoDB中$where操作符是可以执行 JavaScript语句的。
-
在PHP语言中是不能直接写入 JavaScript语句的,需要写在字符串中。使用字符串就会引用到单引号和双引号,因此容易出现闭合的问题
-
在 MongoDB2.4之前,通过$ where操作符使用 map-reduce、 group命令可以访问到 mongo shell中的全局函数和属性也就是说可以操作数据库中的数据。
-
在$query中使用了$where操作符执行 JavaScript语言,其中$username和 $password使用了字符串拼接的方式
所以可以尝试构造闭合语句 进行注入攻击。 -
根据代码,可以控制 admin和 password进行闭合,构造出 payload
-
如:通过闭合单引号,插入代码:n';return true;var a='
-
提交执行的 Javascript代码为
-
在输入用户名后就返回了true,所以只要输入任意密码就可以成功登陆了。
-
注意:
-
闭合的方法有很多,只要 return的值为真即可。、
-
该注入方法较难,主要是因为 payload不易构造,在有源码的情况下容易构造闭合语句,没有源码只能猜测。
-
$where执行的 JavaScript语句只能进行简单的逻辑操作。
mongo shell拼接注入
-
mongoshell是什么?
-
MongoShell是一个互动的 JavaScript接口的 Mongo DB,可以使用M。 ngo Shell来查询和更新数据以及执行管理操作。可以连接到在运行的 MongoDB实例
-
产生的原因
-
PHP中,通过** executeCommand** 可以执行she命令,可以直接执行语句。同样是存在字符串拼接的问题,因此通过使用单引号、双引号构造闭合语句 ,就可以执行任意的语句。
-
危害
-
可以通过构造的语句对数据库进行任意操作,包括增删改查。
-
因为 mongo shell的语句比较好猜测,所以构造 payload的难度不高,且危害较大。
- 以上图代码为例,$cmd是根据时间排倒序,其中$username采用字符串拼接的方式,因此可以构造双引
号闭合攻击,之后通过 executeCommand 可以直接执行语句,造成攻击