Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
操作系统
MacOS 10.10+
Windows x64
Linux
RHEL/CentOS 6 以及更高版本
Ubuntu 14 以及更高版本
Debian 6 以及更高版本
其他 glibc >= 2.12 的发行版
Web 服务器 - 支持 docker 部署
Tomcat 5 ~ 10
Jetty 7 ~ 9
JBoss 4 ~ 8
Wildfly 8 ~ 16
JDK 版本
Oracle JDK 6~15
OpenJDK 6~11
数据库
MySQL
SQLServer
SQLite3
Oracle
SAPI 支持范围(同时支持TS/非TS版本)
PHP-FPM
Apache PHP 模块
操作系统
Linux
PHP 5.3 ~ 5.6,7.0 ~ 7.3
Ubuntu 14.04 以及更高版本
RHELL/CentOS 6 以及更高版本
其他 glibc >= 2.12 的发行版
Mac OS
Homebrew PHP 5.6,7.0 ~ 7.3 (没有深入测试)
数据库
MySQL (mysql/mysqli/PDO 等连接方式)
PostgreSQL
SQLite3
操作系统
Linux
CentOS 6 以及更高版本
Ubuntu 14.04 以及更高版本
后台基于Golang开发,只要不是太老的系统一般都支持
SpringBoot 1 ~ 2 (内置 tomcat/jetty/undertow)
WebSphere 7.X 及以上版本
部分版本由于 IBM JDK 自身限制,无法启用文件读写删改相关检测(可自行更换 Oracle JDK)
商业版不受影响,可正常检测漏洞
WebLogic 10.3.6 / 12.2
宝兰德BES 9.5.X
中创InforSuiteAS 10.0.X
DB2
HSQLDB (WebGoat 使用的嵌入数据库)
Mac OS X
OpenRASP 支持私有化部署,包含客户端与服务端两个组件。在接入之前,请先阅读 兼容性说明 文档,检查客户端是否支持你的应用服务。
第一步: 下载最新版本的安装包
常用镜像
文件说明
第二步: 安装管理后台 (可选)
OpenRASP 支持单机防护,也支持远程管理。若要开启远程管理,请先参考 安装管理后台。
第三步: 安装客户端
取决于你的服务器类型,请参考不同的子章节进行安装。比如 Tomcat 可以查看 进行操作。
第四步: 安装测试用例(可选){#step4}
如果你需要测试漏洞检测效果,请参考 安装漏洞环境。
第五步: 安装IAST扫描工具(可选){#step5}
如果你需要安装扫描工具,请参考 页面进行安装和配置。
开发相关
常见问题
1. 常见自动安装失败原因
Java 版本
关于 java 不重启安装,卸载:由于不支持不重启升级,所以在不重启安装然后不重启卸载之后,想要再次安装需要重启服务器安装。
PHP 版本
2. OpenRASP 无法拦截攻击
Java 服务器
首先,使用浏览器访问网站,检查服务器是否启动成功
若服务器没有启动,可检查启动日志,寻找堆栈信息。对于 tomcat 通常是 catalina.out
根据子章节的文档,检查 OpenRASP 是否安装成功
PHP 服务器
首先,使用浏览器访问网站,检查服务器是否启动成功
若服务器没有启动,可检查 PHP/Apache/Nginx 错误日志
根据子章节的文章,检查 OpenRASP 扩展是否安装成功
3. jnotify 无法释放
有的公司会定制应用启动脚本,比如 catalina.sh,当以root启动tomcat,他会自动切换到低权限用户,再继续启动
通常,你会看到如下的堆栈错误
这说明 OpenRASP 在释放 jnotify 动态链接库时出错(用来监控插件目录变更),错误原因是 Permission denied
所以,你可能需要调整下RASP目录权限,e.g chmod 777 -R rasp,然后再次启动 tomcat
4. Could not find or load main class com.baidu.rasp.App 错误
QQ群用户反馈,执行 RaspInstall 时报错,
经过排查,这是因为当前目录本身没有读取权限导致的,执行 chmod 777 $PWD 后解决。
5. APM 兼容性说明
如果你同时使用 OpenRASP 和 APM 产品,比如 ,那你需要增大 -XX:MaxPermSize 参数。否则运行一段时间后可能会出现 java.lang.OutOfMemoryError: PermGen space 错误,产生大量GC,最终导致服务器假死。
如果原先没有配置过此参数,我们建议你设置为 1024m;如果配置过,我们建议在原先基础上增加至少 512m。
另外,为了避免APM回滚钩子,请将我们的 -javaagent 参数放在前面。
6. JDK9 以上安装问题
由于JDK9以上版本的 Modularity System 属性,需要在手动安装后为服务器添加以下 Java 启动参数:
7. 常见 v8 加载失败原因
7.1 java.io.IOException: Permission denied 异常
如果 /tmp 目录没有写权限,Java 会抛出 java.io.IOException: Permission denied 异常,e.g
此时请检查 /tmp 是否有写权限,以及是否有安全防护软件对 /tmp 目录增加了写保护。
7.2 libopenrasp_v8_java.so: failed to map segment from shared object: Permission denied
对于以下两种场景,
机器开启了SELinux,不允许Tomcat加载不符合策略的动态链接库
so释放目录没有执行权限,比如使用了 noexec 参数挂载
Java可能会出现无法加载so的情况,并提示无法创建区段映射:
解决方法是关闭SELinux(如果开启),并去掉释放目录的noexec挂载(如果有)。如果不是上述两种情况,请加入QQ群联系我们排查。
7.3 java.io.IOException: Couldn't load library openrasp_v8_java
如果你在不支持的系统架构上运行OpenRASP(比如aarch64),可能会看到 Couldn't find resource 错误:
目前我们仅支持x64/x86_64两类架构,其他架构会逐步支持
7.4 java.lang.UnsatisfiedLinkError 错误
如果释放的 libopenrasp_v8_java.so 无法加载,Java 会抛出如下异常:
目前已知的情况有:
JDK是32位的,没有安装32位的glibc运行库。在CentOS系统下可以安装 glibc.i686 软件包。
JDK是64位的,且在 docker alpine 环境里无法启动。这个因为你没有装 libcurl libstdc++ 两个软件包。
如果是其他情况,请加入联系我们。
8. libzip.so 崩溃问题
Java 在运行时可能会产生这个错误:
OpenRASP会定期读取jar包里的pom信息,获取应用所使用的类库和版本。这个是JDK自身的BUG,与OpenRASP无关。你可以通过如下几种方式解决问题:
方案1: 升级JDK版本
根据用户反馈,JDK 1.8 Update 261 没有这个问题。
方案2: 关掉jar包的内存映射
这可能因为Java在读取jar包时,对应的文件已经被修改,导致JVM崩溃,具体可以参考。
通过增加如下JVM启动参数可以解决问题,但可能带来额外的性能损耗:
方案3: 关闭依赖库采集功能
参考 文档,将 dependency_check.enable 设置为 false 即可。
另外,也可以在执行RaspInstall安装的时候增加 -nodep 参数,程序会自动将 dependency_check.enable 改为 false。
方案4: 避免多个Java进程使用相同的业务jar包
有用户反馈,他们的业务存在多个容器共用jar的问题,将jar打包到容器内部就没有这个错误了。
X-Protected-By: OpenRASP方法二: 检查启动日志里是否有 OpenRASP Engine Initialized 字样
检测测试用例是否支持
对于官方测试用例,若无法拦截,则说明存在绕过或者bug
对于其他测试用例,请联系QQ群群主,我们会检查
X-Protected-By: OpenRASP方法二: 创建内容为 <?php phpinfo(); ?> 的PHP文件并访问,检查页面中是否包含 openrasp 扩展信息?
检测测试用例是否支持
对于官方测试用例,若无法拦截,则说明存在绕过或者bug
对于其他测试用例,请联系QQ群群主,我们会检查
rasp-cloud.tar.gz
管理后台,Linux 版本
rasp-cloud-mac.tar.gz
管理后台,Mac 版本
rasp-java.tar.gz
JavaAgent,Linux 版本
rasp-java.zip
JavaAgent,Windows 版本
rasp-php-linux.tar.bz2
PHP Agent,Linux NTS 版本
rasp-php-linux-ts.tar.bz2
PHP Agent,Linux TS 版本
10001
未找到插入 JAVA_OPTIONS 的标志
10002
未找到服务器根目录,e.g 使用了不存在的目录
10003
未找到启动脚本,e.g bin/catalina.sh
10004
无法识别应用服务器类型
10005
命令行参数错误
10006
不重启安装,attach 进程失败
20001
fswatch 类库初始化失败,比如 rasp 安装目录没有写权限
20002
日志记录发生异常,比如日志文件没有写权限
20003
申请共享内存失败
20004
php.ini 配置不正确,比如缺少 openrasp.root_dir 配置
20005
JavaScript 插件加载错误
Unable to extract jnotify library (rasp/libjnotify_64bit.so):
java.io.FileNotFoundException: /data/w/tomcat/rasp/libjnotify_64bit.so (Permission denied)
at java.io.FileOutputStream.open0(Native Method)
at java.io.FileOutputStream.open(FileOutputStream.java:270)
at java.io.FileOutputStream.<init>(FileOutputStream.java:213)
at java.io.FileOutputStream.<init>(FileOutputStream.java:101)$ java -jar RaspInstall.jar -install /usr/local/tomcat/
Error: Could not find or load main class com.baidu.rasp.App--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMEDjava.lang.ExceptionInInitializerError
at org.scijava.nativelib.NativeLoader.<clinit>(NativeLoader.java:107)
at com.baidu.openrasp.v8.V8.Load(V8.java:25)
at com.baidu.openrasp.plugin.js.JS.Initialize(JS.java:44)
at com.baidu.openrasp.EngineBoot.start(EngineBoot.java:56)
at com.baidu.openrasp.ModuleContainer.start(ModuleContainer.java:78)
at com.baidu.openrasp.ModuleLoader.<init>(ModuleLoader.java:74)
at com.baidu.openrasp.ModuleLoader.load(ModuleLoader.java:103)
at com.baidu.openrasp.Agent.init(Agent.java:93)
at com.baidu.openrasp.Agent.premain(Agent.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:382)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:397)
Caused by: java.io.IOException: Permission denied
at java.io.UnixFileSystem.createFileExclusively(Native Method)
at java.io.File.createTempFile(File.java:2001)
at java.io.File.createTempFile(File.java:2047)
at org.scijava.nativelib.BaseJniExtractor.getTempDir(BaseJniExtractor.java:123)
at org.scijava.nativelib.WebappJniExtractor.<init>(WebappJniExtractor.java:69)
at org.scijava.nativelib.NativeLoader.<clinit>(NativeLoader.java:103)
... 14 morejava.lang.UnsatisfiedLinkError: /var/cache/tomcat/temp/nativelib-loader_4485267645656510327/Classloader.1658314629304.0/libopenrasp_v8_java.so: /var/cache/tomcat/temp/nativelib-loader_4485267645656510327/Classloader.1658314629304.0/libopenrasp_v8_java.so: failed to map segment from shared object: Permission denied
at java.lang.ClassLoader$NativeLibrary.load(Native Method)
at java.lang.ClassLoader.loadLibrary0(ClassLoader.java:1934)
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1817)
at java.lang.Runtime.load0(Runtime.java:810)
at java.lang.System.load(System.java:1088)
at com.baidu.openrasp.nativelib.NativeLibraryUtil.loadNativeLibrary(NativeLibraryUtil.java:340)
at com.baidu.openrasp.nativelib.NativeLoader.loadLibrary(NativeLoader.java:136)
at com.baidu.openrasp.v8.Loader.load(Loader.java:12)
at com.baidu.openrasp.EngineBoot.start(EngineBoot.java:57)
at com.baidu.openrasp.ModuleContainer.start(ModuleContainer.java:78)
at com.baidu.openrasp.ModuleLoader.<init>(ModuleLoader.java:89)
at com.baidu.openrasp.ModuleLoader.load(ModuleLoader.java:117)
at com.baidu.openrasp.Agent.init(Agent.java:94)
at com.baidu.openrasp.Agent.premain(Agent.java:71)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:386)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:401)INFO: Couldn't find resource META-INF/lib/linux_arm64/libopenrasp_v8_java.so
[OpenRASP] Failed to load native library, please refer to https://rasp.baidu.com/doc/install/software.html#faq-v8-load for possible solutions.
java.io.IOException: Couldn't load library openrasp_v8_java
at com.baidu.openrasp.nativelib.NativeLoader.loadLibrary(NativeLoader.java:138)
at com.baidu.openrasp.v8.Loader.load(Loader.java:12)
at com.baidu.openrasp.EngineBoot.start(EngineBoot.java:57)
at com.baidu.openrasp.ModuleContainer.start(ModuleContainer.java:78)
at com.baidu.openrasp.ModuleLoader.<init>(ModuleLoader.java:89)
at com.baidu.openrasp.ModuleLoader.load(ModuleLoader.java:118)ava.io.IOException: Couldn't load library library openrasp_v8_java
at org.scijava.nativelib.NativeLoader.loadLibrary(NativeLoader.java:141)
at com.baidu.openrasp.v8.V8.Load(V8.java:25)
at com.baidu.openrasp.plugin.js.JS.Initialize(JS.java:44)
at com.baidu.openrasp.EngineBoot.start(EngineBoot.java:56)
at com.baidu.openrasp.ModuleContainer.start(ModuleContainer.java:78)
at com.baidu.openrasp.ModuleLoader.<init>(ModuleLoader.java:74)
at com.baidu.openrasp.ModuleLoader.load(ModuleLoader.java:103)
at com.baidu.openrasp.Agent.init(Agent.java:93)
at com.baidu.openrasp.Agent.premain(Agent.java:70)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:382)
at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:397)
Caused by: java.lang.UnsatisfiedLinkError: no openrasp_v8_java in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1886)
at java.lang.Runtime.loadLibrary0(Runtime.java:849)
at java.lang.System.loadLibrary(System.java:1088)
at org.scijava.nativelib.NativeLoader.loadLibrary(NativeLoader.java:136)
... 14 moreStack: [0x00007f3951edb000,0x00007f3951fdc000], sp=0x00007f3951fda2d8, free space=1020k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
C [libc.so.6+0x15a00b] __memmove_ssse3_back+0x6cb
C [libzip.so+0x12b33] ZIP_GetNextEntry+0x53
J 5497 java.util.zip.ZipFile.getNextEntry(JI)J (0 bytes) @ 0x00007f3a15da3c76 [0x00007f3a15da3bc0+0xb6]
J 5495 C1 java.util.zip.ZipFile$ZipEntryIterator.next()Ljava/util/zip/ZipEntry; (212 bytes) @ 0x00007f3a15daebec [0x00007f3a15dae940+0x2ac]-Dsun.zip.disableMemoryMapping=true目前我们对数据库的要求是,
MongoDB 版本大于等于 3.6
ElasticSearch 版本大于等于 5.6,小于 7.0 (ES 7.X 变化较大,暂无计划支持)
具体如何安装数据库,这里不在赘述。
首先,编辑 conf/app.conf 文件,修正 ElasticSearch 和 MongoDB 两个服务器的地址。如果这两个数据库都安装在了本机,且使用默认端口,请跳过此步骤:
关于 MongoDB 认证配置,可参考 mongoDB Linux 认证配置、重置密码、远程登录配置详解 文章操作;如果 MongoDB 有主从,只需要填写主地址。
然后,在终端里执行如下命令,启动后台服务器:
最后,在浏览器里打开 http://your-ip:8086,登录管理后台。其中用户名固定为 openrasp,初始密码为 admin@123。如果不能访问,请检查防火墙设置,或者检查 logs/api/agent-cloud.log 下面的错误信息。
登录成功后,请根据 管理后台 - 添加主机 文档,了解如何添加第一台主机。
在实际场景中,我们需要部署多个服务器,才能处理来自数十万主机的连接。因此,我们将管理后台拆分为 Agent 接口服务器 (AgentServer) 和 前端服务器 (PanelServer)。前者用于跟agent通信,比如心跳、日志上传,可以部署多个;后者用于展示数据、定时报警、修改配置,用户可访问这个后台来查看报警。后者用于发送报警邮件,部署多个会有重复报警的问题,所以目前只能部署一个。
在百度,我们会启动一个前端服务器,
然后在不同的机房,分别启动一个 agent 服务器(使用同一份 conf/app.conf 配置文件即可)
服务器部署完成后,请根据 管理后台 - 设置后台信息 文档,将所有的Agent服务器填入。之后就可以在 添加主机 界面上,生成自动安装命令了。
容量说明: 目前,在2核4GB的主机上,按照3分钟一个心跳计算,大概单台机器可容纳 1000个 客户端。
在使用ES集群时,EsAddr 填写一个服务器的地址即可。我们自动会调用 /_nodes/ 接口获取全部服务器信息并轮询,以避免单点问题。
以下配置均为在 conf/app.conf 中配置
Beego 相关
常用 beego 配置项如下,更多设置请参考 beego官网 文档,
appname
应用名称
无
httpaddr
http 监听IP
0.0.0.0
httpport
http 监听端口
8086
runmode
运行模式,dev 为开发模式,prod 为线上模式
prod
OpenRASP 相关
OpenRASP 可用配置项目如下,
EsAddr
Elasticsearch 服务器地址,多个地址用逗号隔开
http://127.0.0.1:9200
EsUser
Elasticsearch 用户名 (X-Pack)
空
EsPwd
Elasticsearch 密码 (X-Pack)
空
EsTTL
Elasticsearch 数据过期时间,单位/天
365
开启 HTTPS
在 conf/app.conf 中加入以下配置即可,修改后重启后台生效:
请登录到每一台部署了 rasp-cloud 的主机,并按照如下步骤进行升级:
如果是 v1.3.0 之前的后台
备份原来的配置文件,conf/app.conf
下载新的安装包,解压缩到相同目录
检查是否需要更新配置文件
执行命令 ps aux | grep rasp-cloud 找到后台进程 PID
对上述进程发出 HUP 信号,e.g kill -HUP $PID
检查后台是否可以正常访问
如果是 v1.3.0 甚至更高版本的后台
备份原来的配置文件,conf/app.conf
下载新的安装包,解压缩到相同目录
检查是否需要更新配置文件
执行 /path/to/rasp-cloud -s restart
检查后台是否可以正常访问
请登录到后台所在的主机,执行如下命令,根据提示重置密码。目前密码强度要求是 8-50 位,必须包含数字和字母。
请登录到后台所在的主机,执行如下命令即可:
请登录到后台所在的主机,执行如下命令即可:
在百度,我们以小时级别对 MongoDB 和 ElasticSearch 数据库进行备份。其中,MongoDB 需要备份 openrasp 数据库,可以使用 mongodump + mongorestore 实现;ElasticSearch 需要备份如下索引,可以用 snapshot 方式备份:
当然,如果公司有DBA团队,可以考虑托管给他们。
当 AlarmLogMode 设置为 file 时,可使用 Logstash 采集文件日志。Logstash 样例配置如下,使用前请先修正日志路径
日志会打印到 logs/api/agent-cloud.log 里。如果启动时没有增加 -d 参数,我们将同时在前台打印错误消息,e.g
目前定义的错误如下,
错误码 | 说明 :---- | :--- | :--- 30001 | 日志初始化失败,如文件权限问题 30002 | MongoDB 初始化失败,如 MongoDB 地址无法连接、MongoDB 认证失败等等 30003 | ES 初始化失败,如 ES 地址无法连接 30004 | 配置错误 ,如未配置 Domain 30005 | 启动模式错误,启动使用了 agent, panel 之外的,不支持模式 30006 | 管理员密码初始化失败 30007 | geoip 初始化失败,如 geoip 数据库文件权限问题 30008 | 后台管理员用户名密码重置失败 30009 | 创建默认 app 失败 30010 | -d 参数启动后台失败
具体错误信息请查看 nohup 控制台输出
我们目前只兼容 Google Chrome 浏览器。如果页面出现任何问题,请按下 F12 调出开发工具,并检查控制台是否有错误输出。如下图中的红色字样:
如果发现这种问题,请加入QQ群联系我们处理。
如果你搜索的时间范围太大,ES 可能会爆出如下错误:
Result window is too large, from + size must be less than or equal to: [10000] but was [281280]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level setting.
这是因为你搜索的时间范围很大,导致ES需要对大量的数据进行排序。解决方法是打开 config/elasticsearch.yml,修改或者增加 index.max_result_window 配置,将它调整为一个较大的值。当然,修改这个值会消耗更多的内存。
在 Java 版本里,我们使用了 InetAddress 来获取主机名称,如果这个主机名在 /etc/hosts 下面没有对应的记录,Java 将抛出 Unknown host 异常。在这种情况下,我们会将主机名设置为 im-not-resolvable,并让程序继续运行。
解决方法是,在 /etc/hosts 下面为你的主机名添加一条记录:
添加后,重启 Java 服务器生效。再次启动时,我们会注册一个新的agent到后台。
默认情况下,后台监听地址为 0.0.0.0:8086。如果你无法访问服务器,请检查防火墙是否开启对应端口。对于基于 netfilter 的防火墙,你可以执行如下命令开放 8086 端口:
大部分国内邮箱都不支持密码登录,需要申请授权码进行登录。如果你在使用下列邮箱,请参考他们的 FAQ 文档进行配置:
Coremail - 请联系销售
目前,后台使用的索引名称前缀为:
real-openrasp-X (alias)
openrasp-X
如果你在使用 X-Pack,且需要按照索引名称前缀进行授权,可以根据上述规则添加认证。若要查看当前 ES 的索引和别名列表,可访问如下URL:
前端文件在 dist 目录下,如果前端服务器返回 404 则说明这个目录不存在,或者 dist/index.html 不存在。
ES索引里只保存报警信息,误删索引不会导致agent信息丢失。若要完全重置ES,请先删除所有以 real-openrasp-、openrasp- 开头的索引,并重新启动 rasp-cloud 即可。rasp-cloud 会在启动时检查并重新创建索引。
为了避免阻塞,管理后台是异步将报警日志写入 ElasticSearch,因此 API 接口成功不代表报警保存成功。当 ES 服务器磁盘空间占用超过 95%,ES 会拒绝接受日志并抛出 cluster_block_exception 异常:
修复方式请参考 Elasticsearch磁盘占用大于95%时将所有索引置为只读 文章解决。
iast 扫描器使用 websocket upgrade 协议连接管理后台,nginx 需要同时传递 Upgrade 头才能工作:
否则会在管理后台 api/agent-cloud.log 看到如下错误
参考 linux 打开文件数 too many open files 解决方法 修正 limits.conf 里的配置即可,修正后需要重新登录生效。
最后通过 ulimits -n 命令确认即可。
如果后台出现离线主机,请按照如下步骤排查:
检查客户端与后台是否连通。使用 curl 命令访问管理后台,检查是否能访问。
重启 Tomcat/PHP 服务器,检查主机是否上线。
检查客户端主机名、网卡信息是否有变化。如果有,后台信息会跟着变更,并产生一台新的主机。这个问题会在后续版本修正,即固定 rasp_id 到配置目录。
检查管理后台系统时间是否正确。
目前已知的情况有
beego自身存在BUG,如果日志目录被链接到 /dev/null,将会卡住。e.g log/access 目录
OpenRASP 抛弃了传统防火墙依赖请求特征检测攻击的模式,创造性的使用RASP技术(应用运行时自我保护),直接注入到被保护应用的服务中提供函数级别的实时防护,可以在不更新策略以及不升级被保护应用代码的情况下检测/防护未知漏洞,尤其适合大量使用开源组件的互联网应用以及使用第三方集成商开发的金融类应用。
另外,OpenRASP 提供的IAST解决方案,相比于与传统的DAST方案有着革命性提升。漏洞检测无需动态爬虫或者旁路代理,扫描更全面;结合应用探针准确的识别漏洞类型,通过针对性扫描大幅度提升检测效率;商业版新增的动态污点追踪能力,还可以在不扫描的情况下,预判接口是否存在漏洞。
OpenRASP 是经过开源社区大规模验证过的产品,目前客户数量已经过百,QQ群人数超过1800人。如果你在使用过程中遇到任何问题,请加入,联系我们处理。
安装部署
目前,OpenRASP 支持 Java 和 PHP 两种开发语言。更多语言支持计划,请查看 。具体开发排期和版本内容,请关注我们置顶的 页面。
[prod]
EsAddr = http://127.0.0.1:9200
EsUser =
EsPwd =
MongoDBAddr = 127.0.0.1:27017
MongoDBUser =
MongoDBPwd =./rasp-cloud -d./rasp-cloud -type=panel -d./rasp-cloud -type=agent -dEnableHTTPS = true
EnableHttpTLS = true
HttpsPort = 443
HTTPSCertFile = "cert.pem"
HTTPSKeyFile = "cert.key"./rasp-cloud -type=reset%> ./rasp-cloud -s status
/rasp-cloud/
2020/02/11 18:13:39 The rasp-cloud is running!%> ./rasp-cloud -version
/rasp-cloud/
Version: 1.3
Build Time: 2020-02-11 17:56:52
Git Commit ID: d6902d60f8874e7255562544041edbd340e6b676real-openrasp-report-data-{appid}
real-openrasp-attack-alarm-{appid}
real-openrasp-policy-alarm-{appid}
real-openrasp-error-alarm-{appid}
real-openrasp-dependency-data-{appid}input{
file{
path=>[
## 1. 修改该处,将 $cloud-agent-home 替换为部署的 agent 模式后台的根目录
"$cloud-agent-home/openrasp-logs/attack-alarm/attack.log"
]
start_position => "beginning"
type => "attack-alarm"
codec => "json"
}
file{
path=>[
## 2. 修改该处,将 $cloud-agent-home 替换为部署的 agent 模式后台的根目录
"$cloud-agent-home/openrasp-logs/policy-alarm/policy.log"
]
start_position => "beginning"
type => "policy-alarm"
codec => "json"
}
}
output {
if [type] == "attack-alarm" {
elasticsearch {
## 3. 修改 ES 地址
hosts => "0.0.0.0:9200"
index => 'real-openrasp-%{type}-%{[app_id]}'
timeout => 30
document_type => '%{type}'
}
}
if [type] == "policy-alarm"{
elasticsearch {
## 4. 修改 ES 地址
hosts => "0.0.0.0:8200"
index => 'real-openrasp-%{type}-%{[app_id]}'
timeout => 30
document_type => '%{type}'
action => 'update'
document_id => '%{[upsert_id]}'
doc_as_upsert => true
}
}
}2018/12/14 09:55:11.393 [I] [environment.go:62] ===== start type: default =====
2018/12/14 09:55:11.408 [E] [mongo.go:54] [30002] init mongodb failed: no reachable servers127.0.0.1 myhostnameiptables -I INPUT -p tcp --dport 8086 -j ACCEPThttp://elasticsearch_hostname:port/_cat/indices?v
http://elasticsearch_hostname:port/_cat/alias?vblocked by: [FORBIDDEN/12/index read-only / allow delete (api)]server {
listen 84;
location / {
proxy_set_header Host $http_host;
proxy_pass http://172.17.0.4;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
}2020/02/07 11:37:47.784 [E] [iast.go:147] upgrade err: websocket: the client is not using the websocket protocol: 'upgrade' token not found in 'Connection' header检测能力
MongoDBAddr
MongoDB 连接地址,多个地址用逗号隔开
127.0.0.1:27017
MongoDBName
使用的 MongoDB 的数据库名称
openrasp
MongoPoolLimit
MongoDB 连接池最大限制
2048
MongoDBUser
MongoDB 认证用户名,该用户需要有操作 openrasp 数据库的权限,有认证才需要配置
空
MongoDBPwd
MongoDB 认证密码
空
LogMaxSize
单个日志文件最大大小,超过就rotate当天日志
104857600
LogMaxDays
最多保留多少天的日志
7
MaxPlugins
每个App最多保留多少插件,超过删除最老的
30
CookieLifeTime
登录 cookie 有效期,单位/小时
168
AlarmLogMode
报警日志采集模式,file 模式将日志落地到文件,可配合 logstash 上传到 es;es 模式将日志直接写入到 ES
es
AlarmBufferSize
es 模式下日志缓冲区大小,当日志量过大,缓冲区满的情况下,将会出现日志丢失
300
AlarmCheckInterval
报警检查间隔时间,单位秒 v1.3 开始改为前端配置
120
RequestBodyEnable
access.log中是否包含请求体信息
false
DebugModeEnable
是否开启Debug开关,打印调试信息
false
ErrorLogEnable
是否将错误日志记录到es
false
LogMaxSize
rasp每个日志文件大小(单位:字节)
104857600
LogMaxDays
rasp日志最长保留天数
10
LogPath
rasp日志文件根路径
/home/openrasp/logs
OfflineInterval
rasp主机离线时间判定超时阈值,允许范围为30~31622400(单位:秒)
180
RegisterCallbackUrl
rasp主机注册回调地址,如果失败将不会注册
空

下载 rasp-java.tar.gz 或者 rasp-java.zip 并解压缩。之后进入到解压后的目录中,e.g rasp-20181221
如果你要开启远程管理,请先参考 管理后台 - 添加主机 文档,找到 app_id/app_secret/backend_url 三个关键参数,然后执行如下命令,
如果你只是运行单机版,只需要指定 -install 参数,
这里的 <tomcat_root> 不是 webapps 目录,而是 tomcat 的根目录。没有错误表示安装成功,其他配置请参考 文档。安装后,需要重启 Tomcat 服务器生效。
不重启安装(仅支持 JDK 6-8)
以上方式安装成功之后需要重启服务器,如果在服务器启动的情况下,不重启安装 OpenRASP,需要在以上命令后面增加 -pid 参数指定运行的服务器进程ID:
在 Windows 下面请替换 $JAVA_HOME 为 %JAVA_HOME%
在 Linux 下面,可以使用 bin/catalina.sh stop 来执行 graceful stop
你会在日志里看到类似下面的输出,这表明 Tomcat 将在处理完当前的HTTP后退出
之后参考我们的自动或者手动安装文档,重新安装即可
1. 安装软件
进入到 tomcat 安装目录(绝对路径包含空格将导致启动失败),e.g /opt/apache-tomcat-8.5.6,将 rasp 目录复制过来
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以还需要修改 rasp 目录的权限,e.g
否则你可能在 catalina.out 里看到类似这样的错误,
2. 修改 Tomcat 启动脚本
打开 bin/catalina.sh, 找到如下内容:
修改为如下(增加 -javaagent 项)
对于使用 yum 安装的 tomcat,你需要创建 /etc/tomcat/conf.d/rasp.conf,并写入以下内容
对于JDK9以上版本,还需要增加额外的JDK启动参数,e.g
3. 开启远程管理
如果你不需要远程管理功能,请跳过这个步骤。
首先,请先参考 文档,找到 openrasp.yml 配置文件内容。然后打开 <tomcat_home>/rasp/conf/openrasp.yml,添加或者修改如下内容:
4. 验证安装是否成功
首先重启tomcat服务器。如果安装了管理后台,在管理后台检查主机是否上线即可;如果是单机版,可以按照如下流程检查:
检查响应的请求头是否包含 X-Protected-By 字样,出现则表示安装成功:
如果使用了反向代理,可能不会看到上面的请求头。此时可以检查 rasp/logs/rasp/rasp.log 中是否出现 OpenRASP Engine Initialized 字样,出现也表示安装成功:
如果服务器无法启动,请检查 tomcat 启动日志,看Java是否抛出异常,e.g catalina.out。如果你无法解决问题,请。
1. 安装软件
进入到 tomcat 安装目录,e.g D:\apache-tomcat-8.5.6,将 rasp 目录复制过来
2. 修改 tomcat 配置
2.1 如果是下载的 "32-bit/64-bit Windows Service Installer" 安装包,
请参考,打开 bin/tomcatXw.exe
切换到 Java 标签页,
在 Java Options 下面增加启动参数,注意替换下绝对路径,e.g
对于JDK9以上版本,还需要额外增加如下内容
2.2 如果是下载的 "Windows zip" 安装包
打开 bin\catalina.bat, 找到 :setArgs 处:
在 :setArgs 下增加新的 JAVA_OPTS,e.g
对于JDK9以上版本,还需要额外增加两个JDK启动参数,e.g
3. 开启远程管理
方法同 Linux 版本,在 openrasp.yml 里增加相关配置即可。
4. 验证安装是否成功
重启 tomcat 服务器,然后检查日志文件,一般是 rasp/logs/rasp/rasp.log,如果出现 OpenRASP Engine Initialized 字样,出现则说明安装成功;或者访问一下服务器,检查是否存在 X-Protected-By: OpenRASP 响应头,存在即表示安装成功。
1. Tomcat Windows Service Installer 版本,无法自动安装
服务版本的安装包,没有提供 catalina.sh,只提供了 tomcatX.exe 作为启动工具
请参考,打开 bin/tomcatXw.exe 进行配置
OpenRASP 依赖于如下几个扩展。如果你在使用发行版自带的 PHP 环境,可以使用 yum、apt-get 等工具安装下这些扩展;如果是自己编译的 PHP 环境,则需要在编译阶段开启这些功能。
pdo
pcre
json
java -jar RaspInstall.jar -install <tomcat_root> -backendurl http://XXX -appsecret XXX -appid XXXjava -jar RaspInstall.jar -install <tomcat_root>
# <server_pid> 为 tomcat 进程 id
# $JAVA_HOME 为 jdk 根目录环境变量,如果未指定该环境变量,替换为 jdk 的完整根目录
java -Xbootclasspath/a:$JAVA_HOME/lib/tools.jar -jar RaspInstall.jar -install <tomcat_root> -pid <server_pid>Jan 12, 2018 6:11:55 PM org.apache.catalina.core.StandardWrapper unload
INFO: Waiting for 1 instance(s) to be deallocated for Servlet [jsp]
Jan 12, 2018 6:11:56 PM org.apache.catalina.core.StandardWrapper unload
INFO: Waiting for 1 instance(s) to be deallocated for Servlet [jsp]
Jan 12, 2018 6:11:57 PM org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreadscp -R ~/Downloads/rasp-20170721/rasp .chmod 777 -R raspcom.baidu.openrasp.exception.ConfigLoadException: Fail to extract rasp-log4j.xml, because of: /usr/share/tomcat8/rasp/conf/rasp-log4j.xml (Permission denied)
at com.baidu.openrasp.messaging.LogConfig.extractLogConfigFile(LogConfig.java:153)
at com.baidu.openrasp.messaging.LogConfig.completeLogConfig(LogConfig.java:72)
at com.baidu.openrasp.Agent.loadConfig(Agent.java:91)
at com.baidu.openrasp.Agent.premain(Agent.java:66)elif [ "$1" = "start" ] ; then
if [ ! -z "$CATALINA_PID" ]; thenelif [ "$1" = "start" ]; then
JAVA_OPTS="-javaagent:${CATALINA_HOME}/rasp/rasp.jar ${JAVA_OPTS}"
if [ ! -z "$CATALINA_PID" ]; thenJAVA_OPTS="-javaagent:${CATALINA_HOME}/rasp/rasp.jar ${JAVA_OPTS}"JAVA_OPTS="--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED ${JAVA_OPTS}"
JAVA_OPTS="--add-opens=java.base/java.net=ALL-UNNAMED ${JAVA_OPTS}"
JAVA_OPTS="-javaagent:${CATALINA_HOME}/rasp/rasp.jar ${JAVA_OPTS}"# 云控配置
cloud.enable: true
cloud.backend_url: xxx
cloud.app_id: xxx
cloud.app_secret: xxx
cloud.heartbeat_interval: 180%> curl -v 127.0.0.1:8080
...
X-Protected-By: OpenRASP
X-Request-ID: eb3b8e287de8406bb4bdb9d86bd31f99
...%> grep OpenRASP -ir rasp/logs/
rasp/logs/rasp/rasp.log:2018-05-22 16:13:25,842 INFO [main][com.baidu.openrasp.Agent] OpenRASP Engine Initialized [1.0-SNAPSHOT (build: GitCommit=3da661734e3ad7641cd98e83f32950deaefcacac date=2017-08-14T03:34:41Z)]-javaagent:C:\Program Files\Apache Software Foundation\Tomcat 7.0\rasp\rasp.jar--add-opens=java.base/jdk.internal.loader=ALL-UNNAMED
--add-opens=java.base/java.net=ALL-UNNAMED:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1:setArgs
if "%ACTION%" == "start" set JAVA_OPTS=-javaagent:%CATALINA_HOME%\rasp\rasp.jar %JAVA_OPTS%
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1:setArgs
if "%ACTION%" == "start" set JAVA_OPTS=-javaagent:%CATALINA_HOME%\rasp\rasp.jar --add-opens=java.base/jdk.internal.loader=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED %JAVA_OPTS%
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1下载 rasp-php-linux.tar.bz2 或者 rasp-php-linux-ts.tar.bz2(线程安全版本) 并解压缩。之后进入到解压后的目录中,e.g rasp-php-20180320
如果你要开启远程管理,请先参考 管理后台 - 添加主机 文档,找到 app_id/app_secret/backend_url 三个关键参数,然后执行如下命令,
如果你只是运行单机版,只需要指定 -d 参数,
其中 /opt/rasp 为 OpenRASP 安装目录,用于存储检测插件、报警日志等等,可根据实际情况调整。在某些情况下,php cli 和 php-fpm 使用的 ini 不同,自动安装程序可能会失败。
首先,备份老的扩展,e.g
然后,安装新的扩展,e.g
最后,通过 graceful reload 方式重新加载服务。
针对不同的服务器类型,你需要执行不同的命令,e.g
需要注意的是,请不要直接覆盖 openrasp.so,否则会产生意想不到的内存错误。我们建议使用 重命名方式 来安装新版,以避免出现问题。
在 web 目录下面,我们建立一个 info.php,并填写如下内容
在浏览器里打开这个页面,使用搜索功能,
定位到 extension_dir 字样,确认PHP扩展安装目录
e.g /usr/lib/php/20151012
搜索 Additional .ini files parsed 字样,
如果找到了,我们就在这个目录下面创建一个新的 ini 文件,e.g /etc/php.d/z-openrasp.ini
如果找不到,就定位到 Loaded Configuration File 字样,确认 ini 配置文件路径
e.g /etc/php.ini
首先,根据你的 PHP 版本号,复制正确的 openrasp.so 到扩展目录,e.g
然后,确定 OpenRASP 安装目录,在这里我们使用 /opt/rasp
这个目录将会用于存储检测插件、报警日志、插件日志等内容,需要手动创建,并保证 PHP 进程可以写入,e.g
由于报警日志存储在 /opt/rasp/logs,我们建议挑选一个空间较大的分区,以避免将根分区打满
最后,修改 php.ini,或者创建 z-openrasp.ini 文件,添加如下内容:
其中,openrasp.root_dir 表示刚才选择的 OpenRASP 安装目录,不填写则无法加载。对于其他配置参数,可参考其他配置文档进行调整。
点击这里下载官方插件 plugins/official/plugin.js,并放置到 <openrasp.root_dir>/plugins/ 目录,下载后自动加载并生效。
访问刚才创建的 info.php,检查 openrasp 模块是否加载成功即可,e.g
如果你没有看到类似的信息,则说明扩展加载失败。常见原因有
PHP版本和扩展版本不一致,比如 PHP 是 5.3 版本,但你安装了 PHP 5.6 版本的 openrasp.so
INI 配置不正确,请参考 php error.log 里的错误消息
所有的错误消息都以 [OpenRASP] 错误码 开头,方便和其他日志进行区分
对于 apache/nginx,可以查看类似 /var/log/nginx/error.log 的路径
确认安装成功后,请删除 info.php 这个文件,以避免泄露敏感信息。
我们只支持 Homebrew PHP 5.6 版本,安装过程同 Linux 系统,aka
复制 dylib 文件到 PHP 扩展目录
修改 INI 配置文件
重启 php-fpm 生效
另外,MacOS 版本不支持远程管理。
OpenRASP 扩展跟 xdebug 模块存在冲突,若同时开启了 xdebug 模块,请先禁用它
在 openrasp 扩展初始化时,我们创建了文件监控线程,用于插件目录的监控。当我们发现插件目录发生变化,就会通过发送 USR2 信号的方式,通知 php-fpm master process 去重新加载子进程,即 gracefully reload。
然而,如果你在启动 php-fpm 的时候,没有使用 -F 参数,则意味着 php-fpm 会主动 fork() 到后台。此时,我们创建的文件监控线程就会失效,也就无法监控插件目录了。
解决方法就是使用 php-fpm -F 这样的方式启动PHP服务器。当然,如果你使用发行版自带的 php-fpm,通常都是这样启动的,无需担心。
默认情况下,OpenRASP会被安装到/opt/rasp,以下用<openrasp.root_dir>代替。你需要检查<openrasp.root_dir>/rasp/logs目录是否存在,以及是否有写权限。
常见没有权限的原因有:
使用了root账号安装OpenRASP,而应用使用低权限账号运行(比如nobody)。
可以执行chmod 777 -R <openrasp.root_dir>/logs增加权限
也可以使用chmod修改上述目录的属主(更加安全)
开启了LSM
对于CentOS/RHEL系统,请检查SELinux是否开启。如果开启,可执行setenforce 0关闭
对于Debian/Ubuntu系统,请检查AppArmor是否开启。如果开启,可以修改php-fpm、apache进程的加固配置
开启了open_basedir配置
我们使用PHP Stream方式写入日志,需要将日志目录加到open_basedir白名单里。如果没有加入,将会看到类似这样的错误
由于nginx/php-fpm/apache都可以修改php的配置,建议在网站根目录下放置phpinfo来检查该配置项,要比命令行准确
如果依然无法解决问题,请检查 php error_log 是否有 OpenRASP 相关的错误日志
如果没有配置过,请在 php.ini 里开启,e.g error_log = /tmp/php_error.log
systemd 会限制应用栈的大小,导致 openrasp 无法启动。你通过修改 /usr/lib/systemd/system/httpd.service,并提高 LimitStack 的值来解决问题。经过测试,我们发现将栈大小限制改为 16MB 可以解决问题,对应的配置为:
当然,直接使用命令行启动 apache 是没有这个问题的,因为他会继承系统默认的 limit 配置,即 unlimited。
OpenRASP 依赖于多个PHP扩展,json、pdo、pcre 等等。由于 PHP 不会严格按照依赖顺序去加载扩展,所以当 openrasp 先于 json 加载,就会产生这个错误,e.g
解决方法就是让 openrasp 扩展最后加载。常见的做法是调整配置文件的权重,比如将 openrasp 配置文件改为 /etc/php.d/z-openrasp.ini,这样 json 配置文件就会先于 openrasp 配置文件加载,就解决了扩展依赖的问题。
当PHP服务器处理过至少一次请求后,我们才能够检测到 webroot,之后才会启动敏感目录检测功能。为了保证性能,该检测点具有如下限制:
只会检测根目录,子目录不会处理
最多在内存里缓存 256 个不同的 webroot 路径,超过这个限制时,只保留已有的路径
根据QQ群用户反馈,增加软连接可以解决问题:
执行如下命令,如果返回 bool(true) 则是线程安全(TS)版本
当然也可以编写PHP脚本来测试,如果页面返回 bool(true) 则是线程安全(TS)版本
php install.php -d /opt/rasp --backend-url http://myserver:port --app-secret XXX --app-id XXXXphp install.php -d /opt/raspmv /usr/lib64/php/modules/openrasp.so /usr/lib64/php/modules/openrasp.so.bakcp openrasp.so /usr/lib64/php/modules/openrasp.soPHP-FPM 服务器
killall -USR2 php-fpm
Apache HTTPD 服务器
apachectl -k reload<?php phpinfo();?> cp php/linux-php5.4-x86_64/openrasp.so /usr/lib/php/20151012
chmod 755 /usr/lib/php/20151012/openrasp.somkdir -p /opt/rasp
chmod 777 -R /opt/rasp; BEGIN OPENRASP
[openrasp]
extension=openrasp.so
openrasp.root_dir=/opt/rasp
; 远程管理配置,不需要不用配置
; openrasp.backend_url=
; openrasp.app_id=
; openrasp.app_secret=
; openrasp.remote_management_enable=1
; END OPENRASPLimitStack=163840PHP Warning: PHP Startup: Unable to load dynamic library '/usr/lib64/php/modules/openrasp.so' - /usr/lib64/php/modules/openrasp.so: undefined symbol: php_json_encode in Unknown on line 0ln -s /lib64/ld-linux-x64-64.so.2 /lib/php -r "var_dump(ZEND_THREAD_SAFE);"<?php echo var_dump(ZEND_THREAD_SAFE); ?>
** 由于无法在运行时增加 JbossEAP 对 OpenRASP 的运行时依赖,所以无法支持 JbossEAP 的不重启安装 **
** jdk9 ~ jdk11 不支持不重启安装 **
1. 安装软件
进入到 jboss 安装目录(绝对路径包含空格将导致启动失败),e.g /opt/jboss
复制安装包内的 rasp 目录到当前目录,
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以还需要修改 rasp 目录的权限,e.g
2. 配置 JBoss
如果是 JBoss 4-6 (非 EAP 版本),
打开bin/run.sh, 找到任意以 JAVA_OPTS= 为起始的行,e.g
在下面增加 JAVA_OPTS="-javaagent:${JBOSS_HOME}/rasp/rasp.jar ${JAVA_OPTS}",最终效果如下:
如果是 JBoss EAP,
standalone模式
打开bin/standalone.sh,找到# Display our environment处,在下面添加:
domain模式
server-group方式配置rasp
如果按照server-group配置rasp,那么此group下面所有的服务器都会安装rasp,打开domain/configuration/domain.xml文件,找到<server-groups>标签,在需要安装rasp的server-group中找到<jvm>标签添加如下配置:
server方式配置rasp
如果只对某个server-group的特定的server安装rasp,打开domain/configuration/host.xml文件,找到<servers>标签,在需要安装rasp的server中添加如下配置:
3. 开启远程管理
配置方法同 Tomcat 开启远程管理,不再赘述。
4. 验证安装是否成功
重启 JBoss 服务器,观察启动日志中是否出现 OpenRASP Engine Initialized字段,出现则说明安装成功
1. 安装软件
进入到 jboss 安装目录,e.g D:\\jboss
复制安装包内的 rasp 目录到当前目录
2. 配置 JBoss
如果使用Jboss 4~6 (非 EAP 版本),则打开
bin\run.bat;
打开脚本后,找到任意以 set JAVA_OPTS 为起始的行,如:
在下面增加 set JAVA_OPTS=-javaagent:%JBOSS_HOME%\rasp\rasp.jar %JAVA_OPTS%:
如果使用Jboss EAP,
standalone模式
打开 bin\standalone.bat 找到第一次出现rem Setup JBoss specific properties处,在下面添加:
domain模式
方法同 Linux 版本
3. 开启远程管理
配置方法同 Tomcat 开启远程管理,不再赘述。
4. 验证安装是否成功
重启 JBoss 服务器,观察启动日志(默认输出到终端)中是否出现 OpenRASP Engine Initialized字段,出现则说明安装成功;或者访问一下服务器,检查是否存在 X-Protected-By: OpenRASP 响应头,存在即表示安装成功。
1. java.io.ObjectInputStream 错误
这个并不是 OpenRASP 的问题,请尝试更新JDK到最新版本
参考资料
2. JDK 9 以上版本兼容性问题
请参考 JDK9 以上安装问题 手动修改启动参数。我们会尽快修改 RaspInstall 程序,并自动添加这个配置。
3. org.jboss.logmanager.PropertyConfigurator cannot be cast to org.jboss.as.logging.logmanager.ConfigurationPersistence 异常
在JBoss EAP 6.1.0上安装OpenRASP后,JBoss可能会无法启动并打印如下错误:
根据Redhat的描述,有两种解决方法:
升级到 JBoss EAP 6.1.1
手动修正 JBOSS_MODULES_SYSTEM_PKGS 配置,暴露相关的Jar给javaagent
PHP Warning: scandir(): open_basedir restriction in effect. File(/www/rasp/logs/alarm/alarm.log.2018-07-26) is not within the allowed path(s)java -jar RaspInstall.jar -install <jboss_root> -backendurl http://XXX -appsecret XXX -appid XXXjava -jar RaspInstall.jar -install <jboss_root># <server_pid> 为 jboss 进程 id
# $JAVA_HOME 为 jdk 根目录环境变量,如果未指定该环境变量,替换为 jdk 的完整根目录
java -Xbootclasspath/a:$JAVA_HOME/lib/tools.jar -jar RaspInstall.jar -install <jboss_root> -pid <server_pid>cp -R ~/Downloads/rasp-20170721/rasp .chmod 777 -R rasp# Setup JBoss specific properties
JAVA_OPTS="-Dprogram.name=$PROGNAME $JAVA_OPTS"# Setup JBoss specific properties
JAVA_OPTS="-Dprogram.name=$PROGNAME $JAVA_OPTS"
JAVA_OPTS="-javaagent:${JBOSS_HOME}/rasp/rasp.jar ${JAVA_OPTS}"JAVA_OPTS="${JAVA_OPTS} -javaagent:${JBOSS_HOME}/rasp/rasp.jar"<jvm-options>
<option value="-javaagent:<jboss_root>/rasp/rasp.jar"/>
</jvm-options><jvm name="default">
<jvm-options>
<option value="-javaagent:<jboss_root>/rasp/rasp.jar"/>
</jvm-options>
</jvm>set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name=%PROGNAME%set JAVA_OPTS=%JAVA_OPTS% -Dprogram.name=%PROGNAME%
set JAVA_OPTS=-javaagent:%JBOSS_HOME%\rasp\rasp.jar %JAVA_OPTS%set "JAVA_OPTS=%JAVA_OPTS% -javaagent:%JBOSS_HOME%\rasp\rasp.jar"14:27:19,691 ERROR [org.jboss.as.controller.management-operation] (ServerService Thread Pool -- 11) JBAS014612: Operation ("add") failed - address: ([
("subsystem" => "logging"),
("console-handler" => "CONSOLE")
]): java.lang.ClassCastException: org.jboss.logmanager.PropertyConfigurator cannot be cast to org.jboss.as.logging.logmanager.ConfigurationPersistence
at org.jboss.as.logging.logmanager.ConfigurationPersistence.getOrCreateConfigurationPersistence(ConfigurationPersistence.java:93)
at org.jboss.as.logging.logmanager.ConfigurationPersistence.getOrCreateConfigurationPersistence(ConfigurationPersistence.java:81)
at org.jboss.as.logging.LoggingOperations$LoggingOperationStepHandler.execute(LoggingOperations.java:154)
at org.jboss.as.controller.AbstractOperationContext.executeStep(AbstractOperationContext.java:440) [jboss-as-controller-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
at org.jboss.as.controller.AbstractOperationContext.doCompleteStep(AbstractOperationContext.java:322) [jboss-as-controller-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
at org.jboss.as.controller.AbstractOperationContext.completeStepInternal(AbstractOperationContext.java:229) [jboss-as-controller-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
at org.jboss.as.controller.AbstractOperationContext.executeOperation(AbstractOperationContext.java:224) [jboss-as-controller-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
at org.jboss.as.controller.ParallelBootOperationStepHandler$ParallelBootTask.run(ParallelBootOperationStepHandler.java:334) [jboss-as-controller-7.2.0.Final-redhat-8.jar:7.2.0.Final-redhat-8]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [rt.jar:1.7.0_79]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [rt.jar:1.7.0_79]
at java.lang.Thread.run(Thread.java:745) [rt.jar:1.7.0_79]
at org.jboss.threads.JBossThread.run(JBossThread.java:122) [jboss-threads-2.1.0.Final-redhat-1.jar:2.1.0.Final-redhat-1]1. 安装软件
进入到 jetty 安装目录,e.g /opt/jetty
复制安装包内的 rasp 目录到当前目录,
cp -R ~/Downloads/rasp-20170721/rasp .OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以还需要修改 rasp 目录的权限,e.g
2. 配置 Jetty
这里假设 rasp 目录释放到了 /opt/jetty/rasp/。
修改 java 启动参数,增加 -javaagent 参数(注意将 -jar 放在命令最末尾):
需要注意的是,对于Windows服务器,请修正 -javaagent 参数,比如
3. 开启远程管理
配置方法同 ,不再赘述。
4. 检查 Jetty 是否安装成功
重启 Jetty 服务器,然后检查日志文件,如果出现 OpenRASP Engine Initialized 字样,出现则说明安装成功;或者访问一下服务器,检查是否存在 X-Protected-By: OpenRASP 响应头,存在即表示安装成功。
1. Jetty / JDK 兼容性问题
Jetty 在 linux/windows 下存在很多问题,经常会看到以下几种错误
PWC6345: There is an error in invoking javac
PWC6199: The type java.io.ObjectStream cannot be resolved
以上这些问题大多是JDK、Jetty自身的问题,可通过更换其他小版本来解决。即使没有安装OpenRASP,Jetty运行也是不正常的。在安装 OpenRASP 前,请先保证Jetty是正常运行的
当然,如果安装OpenRASP后导致jetty出错,你可以
chmod 777 -R rasp1. 安装软件
进入到 resin 安装目录(绝对路径包含空格将导致启动失败),e.g /opt/resin
复制安装包内的 rasp 目录到当前目录,
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以还需要修改 rasp 目录的权限,e.g
2. 配置 Resin
注意: 对于集群模式,可能不存在 <server-default> 标签。对于此类情况,请联系研发团队,并确认应该在哪里增加 JVM 启动参数。
如果是 resin 3,
打开conf/resin.conf, 找到 <server-default> 下面的 <jvm-arg> 起始行,e.g
在下面增加:
如果是 resin 4,
打开 conf/cluster-default.xml, 找到 <server-default> 下面的 <jvm-arg-line> 起始行,e.g
在下面增加:
3. 开启远程管理
配置方法同 Tomcat 开启远程管理,不再赘述。
4. 验证安装是否成功
重启 Resin 服务器,观察启动日志中是否出现 OpenRASP Engine Initialized 字样,出现则说明安装成功;或者访问一下服务器,检查是否存在 X-Protected-By: OpenRASP 响应头,存在即表示安装成功。
java -javaagent:/opt/jetty/rasp/rasp.jar -jar start.jar-javaagent:D:\jetty\rasp\rasp.jarjava -jar RaspInstall.jar -install <resin_root> -backendurl http://XXX -appsecret XXX -appid XXXjava -jar RaspInstall.jar -install <resin_root>cp -R ~/Downloads/rasp-20170721/rasp .chmod 777 -R rasp<jvm-arg>-Xmx256m</jvm-arg>
<jvm-arg>-Xss1m</jvm-arg>
<jvm-arg>-Xdebug</jvm-arg>
<jvm-arg>-Dcom.sun.management.jmxremote</jvm-arg><jvm-arg>-javaagent:/opt/resin/rasp/rasp.jar</jvm-arg><jvm-arg-line>${jvm_args}</jvm-arg-line>
<jvm-mode>${jvm_mode}</jvm-mode><jvm-arg>-javaagent:/opt/resin/rasp/rasp.jar</jvm-arg>我们支持 war 包、jar 包两种部署模式。如果是 war 包的形式,直接参考相应服务器文档即可;如果是内嵌服务器的 jar 包形式,请参考本文档安装。对于 WebGoat 项目,对应的 jar 包通常为 webgoat-XXX.jar。
从 v1.2.0 版本开始,我们加入了 SpringBoot 半自动安装支持。之前的版本请参考手动安装章节。
1. 安装软件
SpringBoot 没有提供通用的启动脚本,所以我们的半自动安装程序只会释放文件。在解压缩后,首先进入到解压后的目录中,e.g rasp-20181221
如果你要开启远程管理,请先参考 管理后台 - 添加主机 文档,找到 app_id/app_secret/backend_url 三个关键参数,然后执行如下命令,
如果你只是运行单机版,只需要指定 -install 参数,
这里的 <spring_boot_folder> 通常是 XXX.jar 包所在的目录。具体 jar 的名字请咨询业务线。
2. 配置启动参数
假设 spring_boot_folder 目录为 /opt/spring-boot/。
修改 SpringBoot 启动参数,增加 -javaagent 绝对路径参数(注意将 -jar 放到命令最末尾),e.g
如果JDK版本为6-8,那么启动参数如下配置
如果JDK版本为11,那么启动参数如下配置
3. 检查安装是否成功
访问服务器,检查是否存在 X-Protected-By: OpenRASP 响应头即可。
1. 安装软件
进入到 Spring Boot 所在目录,通常是 jar 所在的目录,e.g /opt/spring-boot
复制安装包内的 rasp 目录到当前目录,
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以还需要修改 rasp 目录的权限,e.g
2. 开启远程管理
配置方法同 ,不再赘述。
3. 配置启动参数
假设 rasp 目录释放到了 /opt/spring-boot/rasp/。
修改 SpringBoot 启动参数,增加 -javaagent 绝对路径参数(注意将 -jar 放到命令最末尾),e.g
如果JDK版本为6-8,那么启动参数如下配置
如果JDK版本为11,那么启动参数如下配置
4. 检查安装是否成功
访问服务器,检查是否存在 X-Protected-By: OpenRASP 响应头即可。
java -jar RaspInstall.jar -nodetect -install <spring_boot_folder> -backendurl http://XXX -appsecret XXX -appid XXXjava -jar RaspInstall.jar -nodetect -install <spring_boot_folder>java -javaagent:/opt/spring-boot/rasp/rasp.jar -jar XXX.jarjava --add-opens=java.base/jdk.internal.loader=ALL-UNNAMED --add-opens=java.base/java.net=ALL-UNNAMED -javaagent:/opt/spring-boot/rasp/rasp.jar -jar XXX.jarcp -R ~/Downloads/rasp-20170721/rasp .chmod 777 -R raspjava -javaagent:/opt/spring-boot/rasp/rasp.jar -jar XXX.jarjava --add-opens java.base/jdk.internal.loader=ALL-UNNAMED -javaagent:/opt/spring-boot/rasp/rasp.jar -jar XXX.jar复制安装包内的 rasp 目录到 TongWeb 安装目录,比如
D:\tongweb安装目录\rasp
/opt/tongweb安装目录/rasp
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以在 Linux 下还需要修改 rasp 目录的权限,e.g
2.1 方法一: 手动配置 external.vmoptions 文件
打开 Tongweb安装目录/bin/external.vmoptions,然后在其中添加javaagent的配置项:
添加完成后的效果如下图所示(参考红线部分):
配置完成后,重启TongWeb服务器即可生效。
2.2 方法二: 通过TongWeb控制台进行配置
登陆TongWeb的管理控制台,点击左侧 启动参数配置,然后找到 其他jvm参数,添加javagent配置项即可:
添加完成后的效果如下图所示(参考红线部分):
添加完成后点击保存按钮,然后重启TongWeb服务器即可生效。
配置方法同 ,不再赘述。
访问下服务器,检查响应头里是否存在 X-Protected-By: OpenRASP 字样,存在即表示安装成功。当然,如果安装 OpenRASP 后导致TongWeb出错,你可以
chmod 777 -R /opt/tongweb安装目录/rasp-javaagent:${TongWeb_Home}/rasp/rasp.jar-javaagent:${TongWeb_Home}/rasp/rasp.jar

解压缩后,首先进入到解压后的目录中,e.g rasp-20181221
如果你要开启远程管理,请先参考 管理后台 - 添加主机 文档,找到 app_id/app_secret/backend_url 三个关键参数,然后执行如下命令,
如果你只是运行单机版,只需要指定 -install 参数,
这里的 <wildfly_root> 是 wildfly 的根目录。没有错误表示安装成功,其他配置请参考 其他配置 文档。安装后,需要重启 Wildfly 服务器生效。
** 由于无法在运行时增加 Wildfly 对 OpenRASP 的运行时依赖,所以无法支持 Wildfly 的不重启安装 **
1. 安装软件
进入到 wildfly 安装目录(绝对路径包含空格将导致启动失败),e.g /opt/wildfly-9.0.1.Final,将 rasp 目录复制过来
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以还需要修改 rasp 目录的权限,e.g
2. 修改 Wildfly 启动脚本
如果是standalone模式
打开 bin/standalone.sh, 找到如下内容:
在其下面增加如下内容:
如果是domain模式
server-group
如果按照server-group配置rasp,那么此group下面所有的服务器都会安装rasp,打开domain/configuration/domain.xml文件,找到<server-groups>标签,在需要安装rasp的server-group中找到<jvm>标签添加如下配置:
server
如果只对某个server-group的特定的server安装rasp,打开domain/configuration/host.xml文件,找到<servers>标签,在需要安装rasp的server中添加如下配置:
3. 开启远程管理
如果你不需要远程管理功能,请跳过这个步骤。
首先在管理后台找到 app_id、app_secret 两个关键参数,然后打开 <wildfly_home>/rasp/conf/openrasp.yml,添加或者修改如下内容:
4. 验证安装是否成功
重启 wildfly 服务器,然后检查 rasp/logs/rasp/rasp.log 中是否出现 OpenRASP Engine Initialized 字样,e.g
或者检查响应的 Header 是否包含 X-Protected-By 字样,e.g
出现则表示安装成功
1. 安装软件
进入到 wildfly 安装目录,e.g D:\wildfly-9.0.1.Final,将 rasp 目录复制过来
2. 修改 wildfly 配置
如果是standalone模式
打开 bin\standalone.bat, 找到 rem Setup JBoss specific properties 处:
在其下增加如下内容:
如果是domain模式
方法同 Linux 版本
3. 开启远程管理
方法同 Linux 版本,在 openrasp.yml 里增加相关配置即可。
4. 验证安装是否成功
重启 wildfly 服务器,然后检查日志文件,一般是 rasp/logs/rasp/rasp.log,如果出现 OpenRASP Engine Initialized 字样,出现则说明安装成功;或者访问一下服务器,检查是否存在 X-Protected-By: OpenRASP 响应头,存在即表示安装成功。
java -jar RaspInstall.jar -install <wildfly_root> -backendurl http://XXX -appsecret XXX -appid XXXjava -jar RaspInstall.jar -install <wildfly_root>cp -R ~/Downloads/rasp-20170721/rasp .chmod 777 -R rasp# Display our environmentJAVA_OPTS="$JAVA_OPTS -javaagent:$JBOSS_HOME/rasp/rasp.jar"<jvm-options>
<option value="-javaagent:<wildfly_root>/rasp/rasp.jar"/>
</jvm-options><jvm name="default">
<jvm-options>
<option value="-javaagent:<wildfly_root>/rasp/rasp.jar"/>
</jvm-options>
</jvm># 云控配置
cloud.enable=true
cloud.backend_url=http://XXXX
cloud.app_id=XXXX
cloud.app_secret=XXXX%> grep OpenRASP -ir rasp/logs/
rasp/logs/rasp/rasp.log:2018-05-22 16:13:25,842 INFO [main][com.baidu.openrasp.Agent] OpenRASP Engine Initialized [1.0-SNAPSHOT (build: GitCommit=3da661734e3ad7641cd98e83f32950deaefcacac date=2017-08-14T03:34:41Z)]%> curl -v 127.0.0.1:8080
...
X-Protected-By: OpenRASP
X-Request-ID: eb3b8e287de8406bb4bdb9d86bd31f99
...set JAVA_OPTS=%JAVA_OPTS% -javaagent:%JBOSS_HOME%/rasp/rasp.jar复制安装包内的 rasp 目录到 WebSphere 安装目录,比如
D:\IBM
/opt/IBM/WebSphere/AppServer
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以在 Linux 下还需要修改 rasp 目录的权限,e.g
以 WAS 8.5 为例,在控制台左侧的导航栏里,选择 Servers -> Server Types -> WebSphere Application Server,进入应用列表界面:
选择你要开启 RASP 的应用(这里是 server1),点击进入管理页面。在新页面向下翻,找到 Server Infrastructure -> Process definition,并点击进入:
之后在右侧,点击 Additional Properties -> Java Virtual Machine 进入JVM启动参数编辑界面
最后找到 Generic JVM arguments,开始编辑
如果是 Windows 系统,请填写:
如果是 Linux 系统,请填写:
保存后重启应用生效。
配置方法同 ,不再赘述。
方法1,检查日志中是否出现 OpenRASP Engine Initialized 字样,出现则说明安装成功。比如 /opt/IBM/WebSphere/AppServer/profiles/AppSrv01/logs/server1
方法2,访问下服务器,检查响应头里是否存在 X-Protected-By: OpenRASP 字样,存在即表示安装成功。
当然,如果安装 OpenRASP 后导致 WebSphere 出错,你可以
1. 远程管理无法开启,且日志中出现 java.security.AccessControlException 异常
在 WebSphpere Windows 某些小版本下,比如 8.5.5.0,可能会出现 java 安全异常错误。此时会在 ${WAS_INSTALL_ROOT}/profiles/AppSrv01/logs/native_stderr.log 里看到如下内容:
解决方案是增加相关权限,打开 ${WAS_INSTALL_ROOT}/java/jre/lib/security/java.policy,增加如下内容:
修改后,需要重启 WebSphere 服务器生效。
chmod 777 -R /opt/IBM/WebSphere/AppServer/rasp-javaagent:${WAS_INSTALL_ROOT}\rasp\rasp.jar-javaagent:${WAS_INSTALL_ROOT}/rasp/rasp.jar************ Start Display Current Environment ************
Log file started at: [18-11-13 20:10:08:993 CST]
************* End Display Current Environment *************
Exception in thread "Thread-8" java.security.AccessControlException: Access denied (java.lang.RuntimePermission accessDeclaredMembers)
at java.security.AccessController.checkPermission(AccessController.java:132)
at java.lang.SecurityManager.checkPermission(SecurityManager.java:544)
at java.lang.SecurityManager.checkMemberAccess(SecurityManager.java:1689)
at java.lang.Class.checkMemberAccess(Class.java:117)
at java.lang.Class.getDeclaredConstructor(Class.java:465)
at com.baidu.openrasp.gson.internal.ConstructorConstructor.newDefaultConstructor(ConstructorConstructor.java:82)
at com.baidu.openrasp.gson.internal.ConstructorConstructor.get(ConstructorConstructor.java:66)
at com.baidu.openrasp.gson.internal.bind.MapTypeAdapterFactory.create(MapTypeAdapterFactory.java:128)
at com.baidu.openrasp.gson.Gson.getAdapter(Gson.java:349)
at com.baidu.openrasp.gson.Gson.toJson(Gson.java:574)
at com.baidu.openrasp.gson.Gson.toJson(Gson.java:561)
at com.baidu.openrasp.gson.Gson.toJson(Gson.java:516)
at com.baidu.openrasp.gson.Gson.toJson(Gson.java:496)
at com.baidu.openrasp.cloud.Register$RegisterThread.run(Register.java:50)
at java.lang.Thread.run(Thread.java:773)grant codeBase "file:${was.install.root}/rasp/*" {
permission java.security.AllPermission;
};



复制安装包内的 rasp 目录到 BES 安装目录,比如
D:\bes\rasp
/opt/bes/rasp
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以在 Linux 下还需要修改 rasp 目录的权限,e.g
2.1 方法一: 通过BES控制台进行配置
以 BES 9.5 为例,在控制台左侧的导航栏里,选择 实例信息 -> JVM配置,进入JVM配置页面:
在JVM配置页面向下翻,找到JVM选项,并开始编辑
如果是 Windows 系统,请填写:
如果是 Linux 系统,请填写:
保存后重启应用生效。
2.2 方法二: 手动修改BES的server.config文件
编辑 <bes-home>/conf/server.config 文件,并在 <server>/<java-config>/<jvm-options> 标签下,增加新的 JVM 配置,e.g
保存后重启应用生效。
配置方法同 ,不再赘述。
访问下服务器,检查响应头里是否存在 X-Protected-By: OpenRASP 字样,存在即表示安装成功。当然,如果安装 OpenRASP 后导致 BES 出错,你可以


chmod 777 -R /opt/bes/rasp-javaagent:${BES_HOME}\rasp\rasp.jar-javaagent:${BES_HOME}/rasp/rasp.jar<jvm-options>-javaagent:/opt/bes/rasp/rasp.jar</jvm-options>解压缩后,进入到解压后的目录中(如rasp-20170721),在终端中执行以下命令,
如果你要开启远程管理,请先参考 管理后台 - 添加主机 文档,找到 app_id/app_secret/backend_url 三个关键参数,然后执行如下命令,
如果你只是运行单机版,只需要指定 -install 参数,
安装后,需要重启 WebLogic 服务器生效。
不重启安装
以上方式安装成功之后需要重启服务器,如果在服务器启动的情况下,不重启安装 OpenRASP,需要在以上命令后面增加 -pid 参数指定运行的服务器进程 id,JDK6 - JDK8 样例命令如下,
** jdk9 ~ jdk11 不支持不重启安装 **
进入到需要安装插件的domain目录下,如 e.g /opt/wls122212/base_domain
复制安装包下面的 rasp 目录到当前目录
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以还需要修改 rasp 目录的权限,e.g
非集群方式
打开 bin/startWebLogic.sh, 找到 JAVA_OPTIONS="${SAVE_JAVA_OPTIONS}" 这一行,在该行下增加:
集群方式
方式一:通过weblogic的console
访问weblogic的console,例如:http://10.115.184.54:8001/console/console.portal
环境->服务器,找到要安装的server(本例为Server-0)
点击进入Server-0,选择服务器启动,在参数框中,添加如下配置,保存退出
重启Server-0之后,服务器生效
方式二:通过配置weblogic的config.xml文件
找到<weblogic-home>/user_projects/domains/base_domain/config目录,打开config.xml文件,定位到需要安装rasp的<server>/<server-start>/<arguments>标签,在<arguments>标签内添加javaagent参数。
如果没有相应的标签可以手动添加,e.g
重启安装rasp的server,服务器生效
访问 WebLogic 服务器,检查HTTP响应里是否包含 X-Protected-By: OpenRASP 字样,若出现则表示安装成功。若没有安装成功,请检查 WebLogic 是否有异常日志:
进入 WebLogic Domain 目录,e.g C:\wls12212\user_projects\domains\base_domain,并将压缩包内的 rasp 目录复制过来
非集群模式
打开 bin/startWebLogic.cmd, 找到 set JAVA_OPTIONS=%SAVE_JAVA_OPTIONS%"这一行,在下面增加:
集群模式
同Linux的集群模式
访问 WebLogic 服务器,检查HTTP响应里是否包含 X-Protected-By: OpenRASP 字样,若出现则表示安装成功。若没有安装成功,请检查 WebLogic 是否有异常日志:
Weblogic 10.36版本使用32位的JRockit JDK,若系统缺少32位的glibc,可能无法加载 openrasp.so。解决方法就是安装32位glibc,并再次尝试启动。
对于 CentOS 系统,你需要安装 libgcc.i686,否则会提示找不到 libgcc_s.so.1 错误:
若安装过程中出现 libgcc multilib 版本保护问题,e.g
可尝试先升级 libgcc 到最新版本,再安装32位的 libgcc,e.g
之后尝试启动即可。
java -jar RaspInstall.jar -install <weblogic_domain_home> -backendurl http://XXX -appsecret XXX -appid XXXjava -jar RaspInstall.jar -install <weblogic_domain_home># <server_pid> 为 weblogic 进程 id
# $JAVA_HOME 为 jdk 根目录环境变量,如果未指定该环境变量,替换为 jdk 的完整根目录
java -Xbootclasspath/a:$JAVA_HOME/lib/tools.jar -jar RaspInstall.jar -install <weblogic_domain_home> -pid <server_pid>cp -R ~/Downloads/rasp-20170721/rasp .chmod 777 -R raspJAVA_OPTIONS="-javaagent:${DOMAIN_HOME}/rasp/rasp.jar ${JAVA_OPTIONS}"-javaagent:<agent_directory_full_path>/rasp/rasp.jar<server>
<server-start>
<arguments>-javaagent:/PATH/TO/DOMAIN_HOME/rasp/rasp.jar</arguments>
</server-start>
</server>${DOMAIN_HOME}/servers/<安装rasp的server名字>/logsset JAVA_OPTIONS=-javaagent:%DOMAIN_HOME%\rasp\rasp.jar %JAVA_OPTIONS%${DOMAIN_HOME}/servers/<安装rasp的server名字>/logsyum install -y ligbcc.i686Error: Multilib version problems found. This often means that the root
cause is something else and multilib version checking is just
pointing out that there is a problem. Eg.:
Protected multilib versions: libgcc-4.8.2-8.el6.x86_64 != libgcc-4.4.7-11.el6.i686yum install -y libgcc
yum install -y ligbcc.i686


本文介绍如何通过 Syslog TCP 方式,将日志采集到 Splunk 平台。
在开始之前,我们需要先添加 openrasp 日志类型,否则 Splunk 无法组装超过1KB的日志。
创建或者编辑 ,添加如下内容,并重启 Splunk 服务器以生效:
上述配置添加了一个名为 openrasp 的日志类型,格式为 JSON,单行最大长度 320000 字符,足够使用了。
首先在这里下载控制台插件,安装此插件会自动创建 openrasp 日志类型:
然后在 Splunk 首页左上角,点击 App -> Manage Apps -> Install app from file,点击浏览文件,选中刚才下载的插件,然后勾选 Upgrade app. Checking this will overwrite the app if it already exists 选项,点击上传:
安装成功后,会在首页看到 RASP 应用,
应用界面如图
在 Splunk 首页,点击右上角的 Settings -> DATA -> Data Inputs,然后选择 TCP 类型,并点击 NEW 进入配置界面。在这里,我们输入监听端口,即 514。
选择日志类型时,依然是 openrasp。接着点击 Review,然后点击 Submit 保存即可。
当服务器收到日志,就可以在界面上查看了
其他端口也是可以的,但协议只能是 TCP 类型。
如果是单机版,请根据 的说明,配置至少如下两项:
syslog.enable=true
syslog.url=tcp://X.X.X.X:514
修改后应用重启服务器生效。
如果开启了管理后台,定位到 系统设置 -> 报警设置 -> Syslog 报警设置,在界面上配置即可。
首先点击右上角 设置 -> 系统 -> 服务器设置 -> 电子邮件设置,输入邮件服务器和账号信息,
设置好上面邮箱信息后,可定期搜索报警,并通过邮件方式通知。
打开 Splunk -> 搜索 -> 设置搜索语句 -> 另存为 -> 告警
如果你使用 Syslog UDP 方式采集日志,那么单条日志长度将被限制为 1KB。由于我们的报警日志通常在 2~3 KB,所以会导致报警日志截断
请按照如下步骤进行排查
OpenRASP 是否产生报警日志?
检查 <app_home>/rasp/logs/alarm.log 是否有报警?
OpenRASP 是否将日志发给 Syslog 服务器?
Splunk 是否能收到数据?
在应用服务器上,检查 Splunk 端口是否可连接?
使用 linux logger 命令,模拟发送一条日志到 splunk,splunk 是否能收到?
e.g logger -n X.X.X.X -T -P 514 '{"hello":"world123"}'
Splunk 有日志,但是 OpenRASP app 看不到数据
使用默认的搜索应用,看是否能搜到数据?
检查搜索时间范围是否正确?
[openrasp]
BREAK_ONLY_BEFORE = \d\d?:\d\d:\d\d
SEDCMD-StripHeader = s/^[^{]+//
KV_MODE = json
pulldown_type = true
# Change the default maximum line length (in bytes)
TRUNCATE = 320000







复制安装包内的 rasp 目录到 InforSuiteAS 安装目录,比如
D:\inforsuiteas\rasp
/opt/inforsuiteas/rasp
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以在 Linux 下还需要修改 rasp 目录的权限,e.g
2.1 方法一: 通过 InforSuiteAS 控制台进行配置
以 InforSuiteAS 10.0 为例,在控制台左侧的导航栏里,选择 配置 -> server-config-> JVM设置,进入JVM选项页面:
在JVM选项页面向下翻,找到JVM选项,并开始编辑:
如果是 Windows 系统,请填写:
如果是 Linux 系统,请填写:
保存后重启应用服务生效。
2.2 方法二: 手动修改InforSuiteAS的domain.xml文件
编辑 <com.cvicse.loong.las.installRoot>/as/domains/domain1/config/domain.xml 文件,并在 <domain>/<configs>/<config name="server-config">/<java-config>/<jvm-options> 标签下,增加新的 JVM 配置,e.g
保存后重启应用服务生效。
配置方法同 ,不再赘述。
访问下服务器,检查响应头里是否存在 X-Protected-By: OpenRASP 字样,存在即表示安装成功。当然,如果安装 OpenRASP 后导致 InforSuiteAS 出错,你可以
chmod 777 -R /opt/inforsuiteas/rasp-javaagent:${com.cvicse.loong.las.installRoot}\rasp\rasp.jar-javaagent:${com.cvicse.loong.las.installRoot}/rasp/rasp.jar<jvm-options>-javaagent:${com.cvicse.loong.las.installRoot}/rasp/rasp.jar</jvm-options>

在配置阶段,可以使用 -o 参数将配置文件生成到其他路径,e.g
在启动阶段,可以使用 -c 加载你指定的配置文件,e.g
若启动阶段没有指定配置文件,openrasp-iast 会从如下几个路径寻找,找不到无法启动:
~/openrasp-iast/config.yaml
/etc/openrasp/config.yaml
./config.yaml
目前支持的配置内容如下,修改后需要重启 openrasp-iast 进程生效:
openrasp-iast config -o /path/to/config.yaml -a X -b Y -c Z -m mysql://xxxpreprocessor.max_buffer_size
http服务器接受请求的缓冲区大小, 单位Bytes
104857600
preprocessor.plugin_name
使用的去重插件名
default
scanner.retry_times
扫描请求失败重试次数
3
scanner.max_module_instance
最大并发扫描任务数量
16
database.db_name
数据库名
openrasp
preprocessor.http_port
与rasp agent通信的http服务监听端口
25931
preprocessor.process_num
http服务进程数
2
preprocessor.request_lru_size
每个http服务进程的每个扫描目标对应一个LRU,用于存储32byte hash,总大小: 进程数 * 扫描目标数 * lru_size
1000
preprocessor.api_path
rasp agent发送数据的目标 url的path
/openrasp-result
monitor.schedule_interval
扫描速率自动调整策略执行间隔(s)
1.000
monitor.max_cpu
cpu使用率上限,超过限制会降低并发扫描速率
98
monitor.min_cpu
cpu使用率上限下限,低于该值会增加并发扫描速率
85
monitor.console_port
web管理后台使用的端口
18664
scanner.max_concurrent_request
单个扫描任务最大扫描并发线程数
20
scanner.min_request_interval
每个扫描线程最小扫描请求间隔(ms)
0
scanner.max_request_interval
每个线程最大扫描请求间隔(ms)
1000
scanner.request_timeout
扫描请求超时时间(s)
5
cloud_api.enable
是否上传结果到云控
True
cloud_api.backend_url
云控地址
http://127.0.0.1
cloud_api.app_secret
云控的secret_key
无
cloud_api.app_id
云控的app_id
无
affinity.enable
是否以绑定CPU核心的方式运行
False
affinity.core_num
绑定的核心数量
1
log.level
日志级别,可选: DEBUG INFO WARNING ERROR
INFO
log.path
log文件路径, 为空时使用 /home/user/openrasp-iast/log
空
log.rotate_size
单个日志文件触发rotate的日志大小,单位MB
5
log.rotate_num
rotate文件最多保存份数,不包括当前日志文件
2
database.host
mysql数据库地址
localhost
database.port
mysql端口
3306
database.username
用户名
root
database.password
连接密码
空
openrasp-iast start -f -c /path/to/config.yaml复制安装包内的 rasp 目录到 PAS 安装目录,比如
D:\PAS安装目录\rasp
/opt/PAS安装目录/rasp
OpenRASP 需要在 rasp 目录下释放一些动态链接库,所以在 Linux 下还需要修改 rasp 目录的权限,e.g
2.1 方法一: 手动配置 domain.xml 文件
打开 PAS安装目录/pas6/pas/domains/domain1/config/domain.xml,然后在其中添加javaagent的配置项:
添加完成后的效果如下图所示(参考红线部分):
配置完成后,重启PAS服务器即可生效。
2.2 方法二: 通过PAS控制台进行配置
登陆PAS的管理控制台,点击左侧配置中的server-config,然后找到jvm选项,添加javagent配置项即可:
添加完成后的效果如下图所示(参考红色箭头部分):
添加完成后点击保存按钮,然后重启PAS服务器即可生效。
配置方法同 ,不再赘述。
访问下服务器,检查响应头里是否存在 X-Protected-By: OpenRASP 字样,存在即表示安装成功。当然,如果安装 OpenRASP 后导致PAS出错,你可以


chmod 777 -R /opt/PAS安装目录/rasp -javaagent:${PAS_Home}/rasp/rasp.jar -javaagent:${PAS_Home}/rasp/rasp.jar <openrasp_rootdir>/logs/alarm/*.log值得注意的是,Java 版本当前的报警没有日期,只有日志滚动之后才会有日期,e.g
对于 PHP 版本,报警日志总是会带有日期,e.g
不过,由于 PHP 本身的限制,有些日志还是会打印到 PHP 错误日志里,比如 INI 配置错误。
OpenRASP 包含四类日志,
plugin/plugin-DATE.log
检测插件的日志,e.g 插件异常、插件调试输出
rasp/rasp-DATE.log
rasp agent 调试日志
alarm/alarm-DATE.log
攻击报警日志,JSON 格式,一行一个
policy_alarm/policy_alarm-DATE.log
安全基线检查报警日志,JSON 格式,一行一个
1. 攻击日志格式
当发生攻击事件时,OpenRASP 将会记录以下信息,
rasp_id
RASP agent id
app_id
应用ID
app_name
应用名称
event_type
日志类型,固定为 attack 字样
event_time
事件发生时间
event_level
漏洞级别,范围是 critical/high/medium/low
一个完整的 JSON 日志样例如下:
2. 安全基线检查日志
当检测到不符合安全规范的配置时,OpenRASP 将会记录以下信息:
event_type
日志类型,固定为 security_policy 字样
event_time
事件发生时间
server_hostname
服务器主机名
server_nic
服务器IP
server_type
应用服务器类型
server_version
应用服务器版本
一个完整的 JSON 日志样例如下:
3. 应用行为日志
当你在管理后台 -> 防护设置里,开启 打印「行为日志」,仅用于调试,请勿在线上开启 后,我们会在 plugin.log 里打印应用的行为日志,样例如下:
/tomcat/rasp/logs/alarm/alarm.log
/tomcat/rasp/logs/alarm/alarm.log.2018-12-04
.../opt/rasp/logs/alarm/alarm.log.2018-12-16{
"@timestamp": 1618894722217,
"app_id": "88cce00aa5a5207f2d13250f892bdcb96c46f080",
"app_name": "Demo App",
"attack_count": 2,
"attack_location": {
"latitude": 0,
"location_en": "-",
"location_zh_cn": "-",
"longitude": 0
},
"attack_params": {
"command": "cmd /c calc",
"env": [],
"stack": [
"java.base/java.lang.ProcessImpl.<init>(ProcessImpl.java)",
"java.base/java.lang.ProcessImpl.start(ProcessImpl.java:244)",
"java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1109)",
"java.base/java.lang.ProcessBuilder.start(ProcessBuilder.java:1073)",
"java.base/java.lang.Runtime.exec(Runtime.java:590)",
"java.base/java.lang.Runtime.exec(Runtime.java:414)",
"java.base/java.lang.Runtime.exec(Runtime.java:311)",
"org.apache.jsp._004_002dcommand_002d1_jsp._jspService(_004_002dcommand_002d1_jsp.java:136)",
"org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)",
"javax.servlet.http.HttpServlet.service(HttpServlet.java:741)",
"org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:476)",
"org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:386)",
"org.apache.jasper.servlet.JspServlet.service(JspServlet.java:330)",
"javax.servlet.http.HttpServlet.service(HttpServlet.java:741)",
"org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)",
"org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)",
"org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)",
"org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)",
"org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)",
"org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)",
"org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)",
"org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)",
"org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)",
"org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)",
"org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:668)",
"org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)",
"org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)",
"org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)",
"org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)",
"org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:834)",
"org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1417)",
"org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)",
"java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)",
"java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)",
"org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)",
"java.base/java.lang.Thread.run(Thread.java:831)"
]
},
"attack_source": "127.0.0.1",
"attack_type": "command",
"body": "",
"client_ip": "",
"event_level": "critical",
"event_time": "2021-04-20T12:58:42+0800",
"event_type": "attack",
"header": {
"accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en,zh-CN;q=0.9,zh;q=0.8,la;q=0.7",
"connection": "keep-alive",
"cookie": "JSESSIONID=FA7196A1FDE61D1795DCEB3280890E14",
"dnt": "1",
"host": "127.0.0.1:8080",
"referer": "http://127.0.0.1:8080/vulns/004-command-1.jsp",
"upgrade-insecure-requests": "1",
"user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0"
},
"id": "5f425ea2234ca4d4bcd991108affff8c",
"intercept_state": "log",
"parameter": {
"form": "{\"cmd\":[\"cmd /c calc\"]}",
"json": "{}",
"multipart": "[]"
},
"path": "/vulns/004-command-1.jsp",
"plugin_algorithm": "command_other",
"plugin_confidence": 90,
"plugin_message": "Command execution - Logging all command execution by default, command is cmd /c calc",
"plugin_name": "official",
"rasp_id": "520d19c523509c53025d66e67e394ab2",
"rasp_version": "1.3.6",
"request_id": "c7229f3f91e34e95902c7ada3b17865d",
"request_method": "get",
"server_hostname": "YOUR_COMPUTER",
"server_ip": "127.0.0.1",
"server_nic": [
{
"ip": "192.168.154.1",
"name": "vmnet8"
},
{
"ip": "172.16.177.1",
"name": "vmnet1"
},
{
"ip": "172.24.172.41",
"name": "en0"
}
],
"server_type": "tomcat",
"server_version": "9.0.14.0",
"source_code": "",
"stack_md5": "c0eccc0d41f14fcef3f0a6d7521d0875",
"target": "127.0.0.1",
"upsert_id": "5f425ea2234ca4d4bcd991108affff8c",
"url": "http://127.0.0.1:8080/vulns/004-command-1.jsp?cmd=cmd+/c+calc"
}{
"event_type": "security_policy",
"event_time" : "2017-04-01T08:00:00Z",
"policy_id": "3002",
"server_hostname": "my-bloodly-hostname",
"server_nic": {
{
"name": "eth0",
"ip": "10.10.1.131"
},
{
"name": "eth0",
"ip": "192.168.1.150"
}
},
"server_type": "Tomcat",
"stack_trace": "org.apache.catalina.startup.Catalina.start(Catalina.java)\nsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)\nsun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)\nsun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)\njava.lang.reflect.Method.invoke(Method.java:606)\norg.apache.catalina.startup.Bootstrap.start(Bootstrap.java:294)\norg.apache.catalina.startup.Bootstrap.main(Bootstrap.java:428)\n"
"server_version": "7.0.15",
"message": "Tomcat 不应该以root权限启动",
"policy_params": {
"pid": 1023
}
}2021-01-04 10:11:39,627 INFO [http-bio-8080-exec-2][com.baidu.openrasp.plugin.js.log] http://127.0.0.1:8080/vulns/004-command-1.jsp [official] Read file: /usr/local/apache-tomcat-7.0.78/webapps/vulns/004-command-1.jsp
2021-01-04 10:11:40,882 INFO [http-bio-8080-exec-1][com.baidu.openrasp.plugin.js.log] http://127.0.0.1:8080/vulns/004-command-1.jsp [official] Execute command: cp /etc/passwd /tmp/ [ 'java.lang.UNIXProcess.<init>',
'java.lang.ProcessImpl.start',
'java.lang.ProcessBuilder.start',
'java.lang.Runtime.exec',
'java.lang.Runtime.exec',
'java.lang.Runtime.exec',
'org.apache.jsp._004_002dcommand_002d1_jsp._jspService',
'org.apache.jasper.runtime.HttpJspBase.service',
'javax.servlet.http.HttpServlet.service',
'org.apache.jasper.servlet.JspServletWrapper.service',
'org.apache.jasper.servlet.JspServlet.serviceJspFile',
'org.apache.jasper.servlet.JspServlet.service',
'javax.servlet.http.HttpServlet.service',
'org.apache.catalina.core.ApplicationFilterChain.internalDoFilter',
'org.apache.catalina.core.ApplicationFilterChain.doFilter',
'org.apache.tomcat.websocket.server.WsFilter.doFilter',
'org.apache.catalina.core.ApplicationFilterChain.internalDoFilter',
'org.apache.catalina.core.ApplicationFilterChain.doFilter',
'org.apache.catalina.core.StandardWrapperValve.invoke',
'org.apache.catalina.core.StandardContextValve.invoke',
'org.apache.catalina.authenticator.AuthenticatorBase.invoke',
'org.apache.catalina.core.StandardHostValve.invoke',
'org.apache.catalina.valves.ErrorReportValve.invoke',
'org.apache.catalina.valves.AccessLogValve.invoke',
'org.apache.catalina.core.StandardEngineValve.invoke',
'org.apache.catalina.connector.CoyoteAdapter.service',
'org.apache.coyote.http11.AbstractHttp11Processor.process',
'org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process',
'org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run',
'java.util.concurrent.ThreadPoolExecutor.runWorker',
'java.util.concurrent.ThreadPoolExecutor$Worker.run',
'org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run',
'java.lang.Thread.run' ]request_id
当前请求ID
request_method
请求方法
intercept_state
拦截状态
attack_source
攻击来源 IP
target
被攻击目标域名
server_hostname
被攻击的服务器主机名
server_ip
被攻击目标 IP
server_type
应用服务器类型
server_version
应用服务器版本
path
当前URL,不包含参数
url
当前URL,包含完整GET参数
attack_type
攻击类型
attack_params
攻击参数,包含hook点参数、堆栈等等
attack_source
请求来源
client_ip
客户端真实IP地址,请参考 其他配置选项 进行配置
plugin_name
报告攻击插件名称
plugin_confidence
检测结果可靠性,插件返回
plugin_message
检测结果信息
plugin_algorithm
插件检测算法
header
请求header信息
stack_md5
当前堆栈MD5
body
当前请求的body,如果有
policy_id
匹配的策略编号
policy_params
基线报警额外参数,比如 PID
message
不符合规范的配置说明
stack_trace
当前调用堆栈,某些情况可能为空
编辑配置文件,
PHP 版本一般为: /opt/rasp/conf/openrasp.yml
Java 版本路径为: $APP_HOME/rasp/conf/openrasp.yml
假设我们白名单的需求是这样的:
针对所有URL,关闭 SSRF 检测点
针对 www.baidu.com,关闭所有检测点
针对 pma.baidu.com/phpmyadmin/,关闭 SQL 检测点
我们定位到 hook.white(如果没有可以手动添加)并增加如下内容:
具体检测点的名字(如 ssrf/sql)可以从 alarm.log 报警日志里获取,也可以从 参数说明 里查看:
其中 all 表示关闭所有检测点。
注意: 对于单机版本,Java 版本默认监控了插件目录,当目录里有任何插件发生变化,将会立即重新加载所有插件;PHP 版本默认没有开启 fswatch,所以需要重启 httpd/php-fpm 生效。远程管理版本不受影响,支持插件热加载。
插件安装目录如下,其中 official.js 为官方插件:
Java 版本是 <app_home>/rasp/plugins/
PHP 版本是 <openrasp_rootdir>/rasp/plugins/
打开官方插件,首先定位到如下内容,将 all_log 改为 false。修改后,大部分检测算法都会变成拦截模式:
对于其他算法,如XSS检测,还需要手动调整拦截策略,即修改 action 字段为 block:
之后根据 检测插件 的说明决定是否重启应用服务器。
打开官方插件,首先定位到如下内容,将log_event改为true
开启后,JS插件会把应用的所有行为和堆栈都打印到<rasp_home>/logs/plugin/plugin.log,比如
打开插件目录,将文件复制过来即可。之后根据 检测插件 的说明决定是否重启应用服务器。
状态检查
你可以在插件末尾,打印一条日志,e.g
当插件成功加载后就会执行,并在 plugin.log 里打印这条消息:
若插件有语法错误会打印日志,e.g
打开插件目录,删除指定的文件即可。之后根据 检测插件 的说明决定是否重启应用服务器。
在配置文件里,找到 inject.custom_headers 内容,并修改配置即可。
若要去掉所有响应头信息,可以设置为空数组:
如果你是在 VMWare 虚拟机里测试 OpenRASP,然后插件是放在 VMWare 共享 里的,这个时候 inotify 不会生效,也就无法实时更新插件
这可能是因为 vmhgfs 跟 inotify 本身存在兼容性问题,解决方法就是将整个服务器软件都复制到虚拟机的磁盘上,比如 /root/tomcat/
hook.white:
"*":
- "ssrf"
"www.baidu.com":
- "all"
"pma.baidu.com/phpmyadmin/":
- "sql"{
...
"attack_type": "readFile",
...
}var algorithmConfig = {
// 快速设置
meta: {
// 若 all_log 开启,表示为观察模式,会将所有的 block 都改为 log
all_log: true,
// 若 is_dev 开启,表示为线下环境,将开启更多消耗性能的检测算法
is_dev: false,
// schema 版本
schema_version: 1
},
...var algorithmConfig = {
...
xss_userinput: {
name: '算法2 - 拦截输出在响应里的反射 XSS',
action: 'block',
filter_regex: "<![\\-\\[A-Za-z]|<([A-Za-z]{1,12})[\\/ >]",
min_length: 15,
},
...
}var algorithmConfig = {
// 快速设置
meta: {
// 若 all_log 开启,表示为观察模式,会将所有的 block 都改为 log
all_log: true,
// 若 is_dev 开启,表示为线下环境,将开启更多消耗性能的检测算法
is_dev: false,
// 若 log_event 开启,将打印应用行为信息到 plugin.log
log_event: false,
// schema 版本
schema_version: 1
},
...2022-03-07 15:05:56,658 INFO [http-nio-8080-exec-1][com.baidu.openrasp.plugin.js.log] http://127.0.0.1:8080/ [official] JNDI lookup: ldap://127.0.0.1:1389/a [ 'com.sun.jndi.toolkit.url.GenericURLContext.lookup',
'com.sun.jndi.url.ldap.ldapURLContext.lookup',
'javax.naming.InitialContext.lookup',
'org.apache.logging.log4j.core.net.JndiManager.lookup',
'org.apache.logging.log4j.core.lookup.JndiLookup.lookup',
'org.apache.logging.log4j.core.lookup.Interpolator.lookup',
...]plugin.log('初始化成功')2017-10-18 17:30:34,781 INFO [main][com.baidu.openrasp.plugin.log] [offical] 初始化成功2017-10-18 17:40:01,402 INFO [main][com.baidu.openrasp.plugin.log] org.mozilla.javascript.EvaluatorException: unterminated string literal (plugin.js#335)inject.custom_headers:
X-Protected-By: OpenRASP
# X-Content-Type-Options: nosniff
# X-Frame-Options: deny
# X-XSS-Protection: 1; mode=block
# X-Download-Options: noopeninject.custom_headers:
# X-Protected-By: OpenRASP
# X-Content-Type-Options: nosniff
# X-Frame-Options: deny
# X-XSS-Protection: 1; mode=block
# X-Download-Options: noopen点击后台右上角的 添加主机 -> 基础信息,可获取安装 openrasp.yml 配置文件内容:
如果你有大规模部署的需求,请参考 大规模部署 文档
在 系统设置 -> 黑白名单 -> 添加 下面,可以增加检测点白名单。以 phpMyAdmin 应用为例,如果我们不想对 rasp.baidu.com/phpMyAdmin/ 这个URL进行SQL注入检测,可以参考下图配置,点击保存后生效。
在 系统设置 -> 登录认证 -> 修改登录密码 下面,可以设置新的后台登录密码。目前我们不支持多用户模式,未来会逐步完善。对于新密码,我们的要求是 8-50 位,且同时包含数字和字符,不符合规范的密码会被拒绝。
在界面配置即可。一般情况下,端口写 25 即可,如果服务器支持 STARTTLS,会自动开启加密。如果你使用 465 端口,才需要勾选强制TLS。
常见错误
判定为垃圾邮件:
554 DT:SPM 126 smtp4,jdKowACnCjHT2iVcPGzDAA--.262S3 1545984724,please see http://mail.163.com/help/help_spam_16.htm?ip=xxxxx&hostid=smtp4&time=1545984724
需要授权码:
535 Error: 请使用授权码登录。详情请看: http://service.mail.qq.com/cgi-bin/help?subtype=1&&id=28&&no=1001256
请先参考 创建应用 创建企业应用。
然后点击应用,查看应用详情:
配置中的 Agent ID 就在下图位置:
之后获取配置中的 Corp ID 和 Corp Secret:
打开链接 https://open-dev.dingtalk.com/#/corpAuthInfo ,如下所示为 Corp ID 和 Corp Secret,
推送用户列表 和 推送部门列表 在 钉钉通讯录 中获取,填写用户和部门的 id:
用户 id 点击用户即可获取,如下图所示:
部门 id 点击编辑部门即可获取,如下图所示:
在使用反向代理的情况下,比如 nginx + php-fpm,后端应用看到的请求来源通常是nginx的IP地址。为了解决这个问题,我们一般会在 nginx 配置里增加如下内容,即将客户端真实IP,通过 X-Client-IP 这个请求头传递过来:
因此,当发生攻击时,我们获取这个 ClientIP 的内容,就是攻击者真实IP了。若要从指定的header里获取真实IP地址,请打开 管理后台 -> 系统设置 -> 通用设置,将 真实 IP header 填写为 ClientIP 即可,e.g
之后发生攻击时,我们就可以看到真实IP了:
若要在检测到漏洞时,同时展示应用的源代码,可以在 通用设置 -> 开启反汇编功能 里开启这个功能。当频繁发生攻击时,本功能会有一定的性能损耗,建议只在测试环境开启。
开启后,在获取到应用堆栈的同时,我们还会在 报警详情 -> 漏洞详情 上展示应用源代码,e.g
若要使用我们的 API 接口,请先在 登录认证 -> TOKEN 管理 -> 创建 里创建一个 API KEY,输入备注信息后点击确定保存。
之后请参考我们的 后台接口文档 来了解如何调用接口。

openrasp-iast 是一款灰盒扫描工具,能够结合应用内部hook点信息精确的检测漏洞。传统黑盒扫描器依赖于页面响应检测漏洞,不但需要发送大量的请求,还有误报的可能。对于SSRF、文件上传等漏洞,在页面没有回显、主机没有外网权限的情况下,还可能会漏报。openrasp-iast 很好的解决了上述问题,下面我们来看下如何安装它。
另外,IAST 污点追踪功能已经在开发中,将会跟随商业版本发布。若要了解当前的系统架构,请参考 文档。
我们提供了一整套的测试环境,包含 IAST 扫描器、OpenRASP 管理后台 以及 漏洞测试用例。如果你已经安装了docker-compose, 首先修改 vm.max_map_count
proxy_set_header ClientIP $remote_addr;











从 1.0.0 RC1 开始,大部分配置都可以从云端下发,插件也可以远程升级。不过,由于服务器本身的限制,有些配置还是得在本地设置。具体有哪些配置项目,请参考 其他配置 文档。
服务器地址和端口,这里是 192.168.154.200:9200
要创建的索引名称,这里是 rasp-%{+YYYY.MM.dd}
要使用的数据类型,这里是 attack
报警日志的绝对路径,请参考 日志说明 - 存储路径 文档
以某 tomcat 服务器为例,一个完整的 Logstash 配置示例如下:
更多信息请求参考如下文档:
首先,确认 Elasticsearch 里是否有数据
在命令行里,执行以下命令,
如果返回 count 字段,则说明 Elasticsearch 存在数据。请检查 Kibana 是否配置了错误的 Elasticsearch 地址?
其他情况,比如返回 error 字段,e.g IndexMissingException,则说明 Elasticsearch 里没有数据,需要进一步查看原因。
然后,检查 OpenRASP 是否工作正常
检查 <app_home>/rasp/logs/alarm/*.log* 是否有报警日志?如果没有,可以通过攻击测试用例,来产生一些报警日志。
最后,检查 Logstach 是否正常
如果要采集的路径存在日志,但是 Elasticsearch 里却没有数据,则说明 Logstash 工作不正常。
input 配置的日志路径是否正确?
<logstash_root>/logs 下面是否有 [ERROR] 类型的日志?
input {
file {
path => ["/home/tomcat/rasp/logs/alarm/*.log*"]
start_position => "beginning"
}
}
filter {
json {
source => "message"
}
}
output {
stdout {
codec => rubydebug
}
}
output {
elasticsearch {
hosts => ["192.168.154.200:9200"]
index => "rasp-%{+YYYY.MM.dd}"
}
}curl '192.168.154.200:9200/rasp-*/_count'{"count":420,"_shards":{"total":5,"successful":5,"failed":0}}{"error":"IndexMissingException[[attack] missing]","status":404}然后执行如下命令,即可启动环境:
之后,请按照顺序分别:
访问 http://127.0.0.1:18662/vulns/ 触发PHP测试用例
访问 http://127.0.0.1:18661/ IAST控制台启动扫描 (1.3版本后IAST后台合并到云控后台,此端口的后台删除)
访问 http://127.0.0.1:18660/ 云控后台(账号openrasp/admin@123),左上角选择IAST应用查看扫描结果
本工具仅支持Linux平台,在开始之前,请先确保安装:
OpenRASP 管理后台 版本 >= 1.2.0,并至少有一台在线主机
Python 3.6 或者更高版本
MySQL 5.5.3, 或者更高版本
使用 pip3 安装 openrasp-iast,以及依赖的库:
也可以直接下载 PyInstaller 打包的二进制版本,我们每隔2小时自动更新一次:
配置 MySQL 数据库,建立名为 openrasp 的数据库,并为 rasp@% 授权,密码为 rasp123(建议使用强度更高的密码,这里只是举例)。请用 root 账号连接 mysql 并执行如下语句:
注意: 如果管理后台是 v1.3.0 之前的版本,你可以使用这个命令安装老版本的 openrasp-iast:
打开云控管理后台,左上角选择一个IAST扫描器使用的应用,若没有可以在应用管理创建一个。扫描器检出的报警都可以在这里查看。
然后在 插件管理 里,上传并下发 IAST 插件。若在插件列表里无法看到名为 iast: 2019-XXXX-YYYY 的插件,可以手动从 baidu/openrasp 下载并上传。
接着在 系统设置 -> 防护设置 -> Fuzz 服务器地址 里填入 openrasp-iast 所监听的URL,e.g
这里需要保证你的WebServer(安装agent的机器) 可以访问IAST服务器地址,否则请自行配置代理或调整网络架构
最后在 系统设置 -> 通用设置中,修改检测配置:
[插件] 单个hook点最大执行时间 设置为 5000
开启文件过滤器: 当文件不存在时不调用检测插件 设置为 关闭
LRU 大小 设置为 0
如果使用1.2.2以上版本,还需在 系统设置 -> 应用加固中,修改检测配置:
自定义 X-Protected-By 头 设置为非空
点击保存后,以上配置需要等待一个心跳周期后生效(默认90秒)。如果想要立即生效,请手动重启下 Tomcat/PHP 等服务器。
在云控后台右上角 添加主机 -> Fuzz 工具安装 找到 fuzz 工具安装命令。执行后会自动创建配置文件,并修正云控相关字段:
若要在前台启动,请使用如下命令:
若要在后台启动,请去掉 -f 参数:
openrasp-iast 是被动扫描模式,不会使用爬虫技术去获取URL信息。当 iast.js 下发成功,Java/PHP 内部的探针会自动在请求结束时,将本次请求的参数、hook点信息提交给 openrasp-iast 服务器进行分析,并选择性的 Fuzz 目标。
通常,我们会将 OpenRASP 部署至测试环境,并长期运行。在QA、RD做单元测试、功能测试时自动的进行漏洞检测。检测的目标按照 IP:PORT 或者 HOST 进行分组,每个目标可以有不同的配置。若勾选 自动启动扫描 选项,则会在发现新目标时自动启动扫描任务:
在任何状态下,都可点击 设置 按钮对某个任务进行配置,设置会立即生效。
若要避免扫描某些URL,比如注销页面 /logout.php,可以在 IAST 控制台设置一个正则表达式,e.g
控制台会在保存时自动校验正则表达式是否合法。
openrasp-iast 会自动调节扫描速率,默认最大并发是 20,扫描间隔是 0 ~ 1000ms。若扫描速率过快可能会造成拒绝服务,请谨慎修改。
目前支持的漏洞触发条件均为用户输入的参数直接拼接产生的漏洞,尚不支持非HTTP参数、参数编解码方式触发的漏洞,包含以下类型:
命令注入
目录遍历
PHP eval代码执行
文件上传
文件包含
任意文件读取
任意文件写入
SQL注入
SSRF
Java XXE
openrasp-iast 包含如下几类日志,默认存储路径为 ~/openrasp-iast/logs:
error.log
所有模块的错误日志,ERROR级的日志会打印到这个文件
MainProcess.log
主进程日志
Preprocessor.log
预处理模块日志,包含对rasp agent传入信息的处理日志
Monitor.log
监控模块日志,包含web后台操作、扫描任务启停等日志
Scanner_*
扫描任务日志目录,每个任务对应一个目录,包含主线程日志Scanner.log,和所有插件的日志 plugin_插件名.log
启动失败:
OSError: [Errno 48] Address already in use
指定的http服务端口被占用,检查openrasp-iast是否已在运行,或是其他应用占用了配置项中preprocessor.http_port和monitor.console_port指定的端口
OSError: [Errno 24] Too many open files
文件描述符超过限制,使用 ulimit -n 10240 命令修改当前文件描述符数量限制后再启动
如果是 pip3 安装后没有 openrasp-iast 命令,那么它可能是被安装到了 python3 所在的目录,如 /usr/local/lib/python3.7/bin。
解决方法有:
添加软链接,比如以 root 执行 ln -s /usr/local/lib/python3.7/bin/openrasp-iast /usr/bin 命令
将该目录加入 $PATH,比如在当前shell下执行 export PATH=$PATH:/usr/local/lib/python3.7/bin
请先确认漏洞是否已经修复
如果漏洞未修复,请检查 云控后台 -> 系统设置 -> 通用设置->LRU 大小 的设置是否为 0。
尝试在目标系统进行一些操作,触发一些API接口调用
检查 logs/preprocessor.log 中是否有收到请求信息的日志,如果收到请求依然没有任务,请将 ~/openrasp-iast/logs 打包提交给我们
检查agent端/rasp/logs/plugin/plugin.log 是否有报错,一般插件timeout可能意味着Fuzz 服务器地址配置错误,请参考上文进行配置
如果使用的是官方测试环境,检查agent版本是否 > 1.2
如果是自建靶场,查看~/openrasp-iast/logs/preprocessor.log中的请求日志,检查是否正确获取了hook_info
检查 openrasp-iast 服务器是否能够访问目标地址
扫描器默认会使用 服务器 IP + HTTP头host字段的PORT 方式发起请求
如果扫描器无法直接连接目标地址,你可以改为 HOST 方式扫描
在后台 防护设置 -> 使用 HOST 直接访问的服务 里填入 .* 或者 匹配对应 host 的正则即可,被正则命中的HOST将作为扫描目标地址
iast是被动模式的扫描,在启动扫描后会保持运行状态,对新获取的url进行实时扫描,扫描器无法预知是否还会有新请求被获取,当 总任务=已扫描+已失败 时,所有当前获取到的url已扫描完毕,如果没有继续扫描的需求,手动停止扫描即可
MySQL 默认的最大连接数为 100,启动的扫描进程过多会导致MySQL连接数超过100并报错,只需在 my.ini 文件中添加或修改以下条目增加最大连接数即可
max_connections = 10000
开源版本的IAST使用MySQL来存储扫描任务,并需要开启 lower-case-table-names 配置。由于云上的RDS通常为托管状态,无法修改此选项,所以请单独部署MySQL服务器。
值得注意的是,这个仅影响IAST本身。如果你要扫描的业务使用了云上的RDS,是完全不受影响的。
IAST启动后,持续抛出 ConnectionError: Connection failed, status code:400 异常
检查iast连接的云控是否配置了代理,如nginx等,导致http无法upgrade为websocket;如果配置了http代理,那么需要给websocket也配置相应代理
无论是自研的,开源的还是商业SIEM产品,OpenRASP 都可以无缝集成。
从 v1.3 开始,管理后台支持直接将报警日志写入 Kafka。为了方便你测试,我们还支持推送测试报警。
当管理后台收到报警日志,我们可以立即将日志推送到指定的 HTTP/HTTPS 地址,直接在界面上配置即可。为了方便你测试,我们还支持推送测试报警。
默认情况下,我们会打印 JSON 格式的报警日志、基线日志。你可以通过部署主机agent,来采集日志。目前开源的日志采集工具有 Logstash, Flume, Filebeat 等等。如果你想要使用这种方案,请参考 章节进行配置,其他软件大同小异。
由于单条报警日志大小超过了1KB,所以我们只支持以 Syslog TCP 方式,直接将日志发送到指定的服务器。若要采用这种方式采集日志,请参考 章节进行配置。
值得注意的是,在PHP版本里,syslog 是阻塞发送的。如果因为网络问题,导致syslog远程服务器不可用,发生攻击时会阻塞当前请求。
本表格参考 进行分类,如果你有任何疑惑,或者发现无法拦截的攻击,请;具体每种攻击覆盖哪些场景,可翻到最下面查看详细说明
sudo sysctl -w vm.max_map_count=262144git clone https://github.com/baidu-security/openrasp-iast.git
cd openrasp-iast/docker/iast-cloud
docker-compose uppip3 install --upgrade git+https://github.com/baidu-security/openrasp-iastwget https://packages.baidu.com/app/openrasp/openrasp-iast-latest -O /usr/local/bin/openrasp-iast# 如果是 MySQL 8.X 以及更高版本
DROP DATABASE IF EXISTS openrasp;
CREATE DATABASE openrasp default charset utf8mb4 COLLATE utf8mb4_general_ci;
CREATE user 'rasp'@'%' identified with mysql_native_password by 'rasp123';
grant all privileges on openrasp.* to 'rasp'@'%' with grant option;
grant all privileges on openrasp.* to 'rasp'@'localhost' with grant option;
# 如果是低版本 MySQL
DROP DATABASE IF EXISTS openrasp;
CREATE DATABASE openrasp default charset utf8mb4 COLLATE utf8mb4_general_ci;
grant all privileges on openrasp.* to 'rasp'@'%' identified by 'rasp123';
grant all privileges on openrasp.* to 'rasp'@'localhost' identified by 'rasp123';pip3 install --upgrade git+https://github.com/baidu-security/openrasp-iast@v1.2http://IAST服务器地址:25931/openrasp-resultopenrasp-iast config -a APP_ID -b APP_SECRET -c BACKEND_URL -m mysql://rasp:rasp123@127.0.0.1/openraspopenrasp-iast start -fopenrasp-iast start^/logout\.php.*
本章节介绍 OpenRASP 的主要功能
A1
注入
SQL注入
高危
命令注入
高危
具体请查看以下几篇公众号文章
1. 数据库: SQL注入
覆盖场景:
来自 GET、POST、Header、JSON、Multipart 等参数的SQL注入
其他类型的SQL注入,如二次注入、RPC接口SQL注入
覆盖类型:
盲注、UNION 注入、时间差注入、错误注入、多语句注入
SQL 异常监控: 如语法错误、密码错误
2. 数据库: 慢查询(已废弃)
说明: 在SQL获取数据时,同时获取SQL语句较为困难,目前这个检测点已经废弃;另外,我们无法区分网络耗时和SQL执行时间,难以确认慢查询是不是真的慢查询
期望覆盖场景
SELECT 语句执行时间超过 N 秒
SELECT 语句一次读取数据超过 N 条(容易误报,如数据导出)
3. 任意文件上传
覆盖场景
HTTP PUT 方式上传脚本文件,比如 CVE-2017-12615
HTTP PUT + MOVE 方式,先上传普通文件,再重命名为脚本文件
使用标准的 multipart 方式上传脚本文件
支持 Java struts、spring、common.io 等框架
支持 PHP $_FILES 方式
4. 敏感文件下载、任意文件读取
覆盖场景
利用任意文件下载漏洞,尝试跳出web目录下载系统文件,e.g /download.jsp?path=/../././//./.././/../../etc/hosts
PHP webroot 下存在 .tar/.sql/.log/... 等敏感文件(仅做基线检测,不拦截)
5. 文件目录列出
覆盖场景
使用 PHP WebShell 查看服务器的文件目录
开启了 directory index,使得用户可以直接看到某个目录下的文件(此检查默认不开启)
使用 ../ 获其他变形跳出前目录,查看其它目录内容
6. 扫描器探测行为 [官方插件不支持]
说明: 大部分情况下,发现扫描器行为不代表存在漏洞。这个功能不符合RASP的初衷,所以我们默认关闭了这个功能。若要开启,请下载 002-detect-scanner.js,并参考 检测插件配置 - 安装插件 文档,安装这个插件即可。
覆盖场景
使用知名扫描器探测网站漏洞,e.g SQLMap、WVS 等等
7. CSRF [暂无计划支持]
说明
此类漏洞应该由开发框架来完成。RASP可以通过插入JS的方式来实现,即在JS里面监控form创建,插入csrf token,并在服务端进行token验证
覆盖场景
使用 img/video/frame/.. 等方式,触发GET类型CSRF
Form 表单自动提交的方式
XHR 方式提交表单
8. Cookie 篡改
覆盖场景
修改cookie获取管理员权限
9. CRLF [暂无计划支持]
说明: HTTP header CRLF 注入漏洞大多已经在API层面被修复,我们没有支持的计划;然而在一些非HTTP协议里依然存在,比如最近爆出的 Java FTP 协议CRLF注入。由于我们没有足够的案例,所以暂时不打算支持。
覆盖场景
在设置 HTTP header,或者处理其他TCP流时(比如FTP协议),插入换行符
10. XXE
说明: PHP无法挂钩xml检测点,暂不支持
覆盖场景
通过 org.apache.xerces 引用外部实体
访问 ftp/dict/gopher/expect/.. 等不常见协议,实现OOB攻击
使用 file 协议读取敏感文件
11. 反序列化漏洞
覆盖场景
Java
fastjson
transformer
xstream(如 S2-052)
... (其他未知类型,具体看检测插件 command_reflect 算法)
PHP
待整理
12. Struts OGNL 代码执行
覆盖场景
Struts OGNL 系列所有代码执行漏洞
OGNL 语句注入攻击
13. WebShell 行为
覆盖场景
使用SQL管理器访问数据库
使用文件管理器下载敏感文件
使用中国菜刀执行命令
...
14. 远程命令执行
覆盖场景
使用 Runtime.exec() 类执行命令
使用 system/passthru/shell_exec/proc_open/pcntl_exec/.. 等函数执行命令
通过反序列化等方式执行命令
15. 命令注入
覆盖场景
使用 &、|、; 等符号截断、拼接命令
使用 $(xxx)、反引号等方式注入命令
在命令注入攻击时,产生了语法错误
16. XSS: 反射形式
覆盖场景
使用 PHP echo 函数直接输出 GPC
用户输入含有HTML标签的内容,且直接输出到页面中
17. XSS: 存储型(尚未发布)
覆盖场景
后台盲打
18. LDAP 注入 [仅IAST商业版支持]
覆盖场景
通过注入修改LDAP查询逻辑
19. DOS: Regex Group 攻击 [仅IAST商业版支持]
覆盖场景
常见 Regex DOS 攻击,e.g (a+)+、(a|aa)+
20. 打印敏感日志信息
覆盖场景
使用 log4j、java.util.logging 打印身份证、银行卡、信用卡等敏感信息
HTTP响应(html/json/xml/等等)返回了未打码的敏感信息
21. 文件包含
覆盖场景
PHP 使用 include|include_once|require|require_once 等方式,包含日志、图片、文本文件等等
Java 使用 jstl 等方式包含文件
22. NTLM 信息泄露攻击
覆盖场景(仅限 Windows)
MySQL DNS 方式脱裤
使用 302重定向到file/smb/scp协议 方式,泄露NTLM key
...
23. SSRF
覆盖场景
绕过
使用 10.10.10.10.xip.io / *.vcap.me 等已知域名访问内网资源
使用 302 重定向方式访问 file:// 域的资源
尝试混淆访问的目标地址,且是内网IP,e.g http://0x7f001、http://0x7f.0x0.0x0.0x1
访问保留地址,e.g http://0/
常见场景
尝试访问 aws metadata,e.g http://169.254.169.254/latest/meta-data/
尝试访问已知的回显服务,e.g *.burpcollaborator.net、requestb.in
24. 资产弱点识别 [开源版本仅采集信息,商业版支持漏洞识别]
覆盖场景
采集 composer/pom 信息
使用存在已知漏洞的类库
25. 后台爆破识别
覆盖场景
无验证码的后台爆破
在应用服务器启动时,进行安全配置规范检查。如果 security.enforce_policy 设置为 true,发现不安全配置时,将抛出 com.baidu.openrasp.exception.SecurityException 异常并拒绝应用服务启动
报警只会打印一次,具体格式参考 安全配置检查报警日志 相关文档
** 支持的服务器 **
tomcat
** 策略说明 **
在 tomcat 服务器下,检查是否在 JSESSIONID 是否开启 httpOnly 开关
开启后,将对XSS攻击有一定的防范能力,可避免一些问题
** 修复方法 **
若是 tomcat 7 以下版本,打开 CATALINA_HOME/conf/context.xml,将 useHttpOnly 改为 true,重启应用服务器即可
** 支持的服务器 **
tomcat, jetty, jboss, resin, springboot 等所有的 java 服务器
** 策略说明 **
检查应用服务器的启动账号,当以如下账号启动则认为不符合安全规范:
Linux 系统的 root 账号
Windows 系统的 Administrator 或者 system 账号
当应用服务器存在安全漏洞,以高权限账号启动会带来更大的安全风险,e.g 上传 webshell 即可获取最高权限、利用 struts 漏洞直接获取 root 权限
** 修复方法 **
使用低权限用户启动应用服务器
** 支持的服务器 **
tomcat
** 策略说明 **
在 tomcat 下,检查 $CATALINA_HOME/conf/tomcat-users.xml 下面配置的用户,如果具有 admin,manager,admin-gui,manager-gui 权限之一,即认为是管理员。然后针对所有管理员用户,检查密码的健壮性。
目前策略非常简单,当用户名和密码均是以下内容之一,才认为是弱口令
** 修复方法 **
使用高强度密码,e.g 使用10位以上的密码,并包含数字、字母、特殊符号
** 支持的服务器 **
tomcat
** 策略说明 **
在 tomcat 下,检查 ROOT、manager、host-manager、docs 四个 webapps 是否删除
默认应用或多或少会泄露敏感信息,或者造成管理后台对外暴露的风险
** 修复方法 **
全部删除
** 支持的服务器 **
tomcat
** 策略说明 **
在 tomcat 下检测 $CATALINA_HOME/conf/web.xml 是否为全局开启了 default servlet 的 Directory Listing功能
开启 Directory Listing 功能,会泄露项目的目录结构,并泄露服务器的版本信息,危险配置如下:
** 修复方法 **
打开 $CATALINA_HOME/conf/web.xml 把如上 xml 配置中的名字为 listing 的 init-param 删除,或者把 param-value 改为 false 即可
** 支持的服务器 **
所有使用 JDBC 的服务器、PHP 服务器
** 策略说明 **
检查是否使用 root (mysql)、sa (mssql)、sys (oracle) 等高权限账号连接数据库
当存在SQL注入漏洞,使用高权限账号连接数据库会带来更大风险,泄露更多的数据;当服务器被黑客入侵,使用高权限账号,还可能同时导致数据库服务器沦陷
如果 security.enforce_policy 选项设置为 true,那么无论数据库连接成功与否,我们都会拦截并产生报警;如果设置为 false(默认值),则只有成功的连接才会报警,且对于每个JDBC URL,相同的报警每天只会打印一次
** 修复方法 **
创建新账号,授予最小的权限;不同的服务器集群使用不同的数据库账号连接
** 支持的服务器 **
JBoss 4-6
** 策略说明 **
检查 /jmx-console/HTMLAdaptor 是否开启认证
** 修复方法 **
编辑 $JBOSS_HOME/server/default/deploy/jmx-console.war/WEB-INF/web.xml,开启 security-constraint 相关配置
编辑 $JBOSS_HOME/server/default/deploy/jmx-console.war/WEB-INF/jboss-web.xml,开启 security-domain 相关配置
** 支持的服务器 **
PHP
** 策略说明 **
定期扫描 webroot,检查是否存在后缀为 sql、tar、rar、... 的文件
** 修复方法 **
删除这些文件
从 nginx、apache 层面过滤掉这些扩展名,防止被外界下载
** 支持的服务器 **
PHP 服务器
** 策略说明 **
检查 allow_url_include 是否开启。开启后,将允许包含远程文件,e.g
当应用存在文件包含、任意文件读取等漏洞,开启这个配置会让应用更加容易被入侵。
** 修复方法 **
修改 ini 配置,将 allow_url_include 设置为 Off
** 支持的服务器 **
PHP 服务器
** 策略说明 **
检查 expose_php 是否开启。若开启,在请求响应里可看到PHP的完整版本号,e.g
** 修复方法 **
修改 ini 配置,将 expose_php 设置为 Off
** 支持的服务器 **
PHP 服务器
** 策略说明 **
检查 display_errors 是否开启。当这个选项被开启,用户可在前端看到PHP程序内部的错误消息,e.g
Warning: mysql_fetch_array() expects parameter 1 to be resource, boolean given in C:\wamp\www\post\includes\pm_send.php on line 12
当应用存在漏洞,结合这些错误消息,攻击者可以获取应用运行的路径、进行SQL报错注入攻击等等
** 修复方法 **
修改 ini 配置,将 display_errors 设置为 Off
** 支持的服务器 **
PHP 服务器
** 策略说明 **
检查 yaml.decode_php 是否开启。当这个选项被开启,在加载 yaml 文件的时候,将允许反序列化PHP对象,可能执行任意代码。另外,如果没有安装 yaml 扩展,即使配置了 yaml.decode_php=On 也不会报警。
** 修复方法 **
修改 ini 配置,将 yaml.decode_php 设置为 Off
gopher://、dict 等不常见协议(Java)使用JSTL import方式访问内网资源
LDAP 注入
高危
仅IAST商业版支持
NOSQL 注入
高危
仅IAST商业版支持
XPATH 注入
高危
仅IAST商业版支持
A2
失效的身份认证和会话管理
Cookie 篡改
低危
仅IAST商业版支持
后台爆破
中危
仅IAST商业版支持
A3
敏感数据泄露
敏感文件下载
高危
任意文件读取
高危
数据库慢查询
高危
文件目录列出
低危
A4
XML 外部实体(XXE)
XXE
中危
A5
失效的访问控制
任意文件上传
高危
CSRF
中危
仅IAST商业版支持
SSRF
高危
文件包含
高危
A6
安全配置错误
打印敏感日志信息
低危
Struts OGNL 代码执行
高危
远程命令执行
高危
A7
跨站脚本(XSS)
反射型 XSS
低危
存储型 XSS
高危
仅IAST商业版支持
A8
不安全的反序列化
反序列化用户输入
高危
A9
使用含有已知漏洞的组件
资产弱点识别
低危
A10
不足的日志记录和监控
WebShell 行为
高危
从 v1.3 版本开始,我们加入了类库信息采集功能。Java 版本会采集 POM 信息,PHP 版本会采集 composer.json。值得注意的是,Java 版本在使用了相关的类之后才能获取到,PHP 是在发现新的 webroot 后才会采集。
我们默认每隔6小时采集一次,为了保证时效性,Java 版本会在启动2分钟后提交一次。
遍历所有名字为 "java" 的进程
获取进程相关信息
进程检查: 获取启动参数、环境变量信息,检查是否为 tomcat 进程,如果不是,跳过
端口检查: 尝试获取 tomcat 一个可用的 HTTP 端口,如果找不到跳过当前进程
权限检查: 如果用户为root,使用su进行安装;否则检查进程UID是否和当前用户一致,不一致跳过
用户检查: 检查是否能否获取到当前用户名,获取不到就跳过
版本检查: 检查 tomcat/jdk 是否为支持的范围,不支持就跳过
冲突检查: 检查是否有其他的 javaagent 参数,如果发现且不为 openrasp,就跳过
安装流程
首先执行 RaspInstall.jar 进行安装,如果出错进入回滚流程
然后尝试关闭 tomcat 服务器,最多等待30s
之后尝试启动 tomcat 服务器,并不断尝试访问之前找到的 URL 地址,最多尝试60次
如果失败,进入回滚流程
回滚流程
执行卸载操作,然后启动 tomcat 服务器
如果无法启动,打印错误
最后上传完整的脚本日志,包括安装和回滚(如果有)
当然,在实际上线的过程中,我们还编写了一个打包脚本,用来生成单文件的安装包。有兴趣可以参考 baidu/openrasp - rasp-install/packer 相关脚本。
容器部署通常都需要定制。在百度内部,我们一般是修改 Dockerfile,并在发布镜像时集成 OpenRASP。在执行下面的命令之前,请先在管理后台获取 app_id/app_secret/backendurl 等参数的值。
对于 alpine 容器,需要增加如下内容
如果不能运行,请尝试增加软连接
Tomcat 示例
假设 tomcat 安装路径为 /tomcat/,在服务器启动之前增加 ADD + RUN 命令即可:
SpringBoot 示例
假设 springboot 打包后的jar为 /springboot.jar,请先解压缩 rasp 相关文件,然后修改 JVM 启动参数:
请在 apache/php-fpm 启动前增加如下命令
both
tomcat
admin
123456<servlet>
<servlet-name>default</servlet-name>
<servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
<init-param>
<param-name>debug</param-name>
<param-value>0</param-value>
</init-param>
<init-param>
<!-- 如下就开启了 default sevelet 的 Directory Listing 功能-->
<param-name>listings</param-name>
<param-value>true</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>include("http://xxxxx")X-Powered-By: PHP/5.1.2-1RUN apk add --no-cache gcompat libcurl libstdc++ln -s /lib64/ld-linux-x86-64.so.2 /lib/ld-linux-x86-64.so.2ADD https://packages.baidu.com/app/openrasp/release/latest/rasp-java.tar.gz /tmp
RUN cd /tmp \
&& tar -xf rasp-java.tar.* \
&& /jdk/bin/java -jar rasp-*/RaspInstall.jar -install /tomcat/ -appid XXX -appsecret XXX -backendurl XXX \
&& rm -rf rasp-*ADD https://packages.baidu.com/app/openrasp/release/latest/rasp-java.tar.gz /tmp
RUN cd /tmp \
&& tar -xf rasp-java.tar.* \
&& mv rasp-*/rasp/ /rasp/ \
&& rm -f rasp-java.tar.gz
RUN echo "cloud.enable: true" >> /rasp/conf/openrasp.yml \
&& echo "cloud.backend_url: XXX" >> /rasp/conf/openrasp.yml \
&& echo "cloud.app_id: XXX" >> /rasp/conf/openrasp.yml \
&& echo "cloud.app_secret: XXX" >> /rasp/conf/openrasp.yml
RUN java -javaagent:"/rasp/rasp.jar" -jar /springboot.jarADD https://packages.baidu.com/app/openrasp/release/latest/rasp-php-linux.tar.bz2 /tmp/
RUN cd /tmp \
&& tar -xf rasp-php-linux.tar.bz2 \
&& php rasp-php-*/install.php -d /opt/rasp/ --backend-url XXX --app-id XXX --app-secret XXX \
&& rm -rf rasp-php*如果你安装时使用了自动安装程序,那么卸载的时候你也应该使用自动卸载程序。
仅适用于 tomcat/jboss/resin/weblogic/wildfly 服务器。
进入 rasp 安装包解压目录,e.g rasp-2018-12-20,并执行如下命令
不重启卸载:
不重启卸载 OpenRASP,需要在以上命令后面增加 -pid 参数指定运行的服务器进程 id,JDK6 - JDK8 样例命令如下,
jdk9 ~ jdk11 样例命令如下,
注意:不重启卸载之后,若想再次安装不能使用不重启安装,只能使用需要重启的安装方式
进入 rasp 安装包解压目录,e.g rasp-2018-12-20,并执行如下命令
假设Tomcat根目录为${CATALINA_HOME}
删除目录${CATALINA_HOME}/rasp
找到启动配置文件
Linux环境下打开${CATALINA_HOME}/bin/catalina.sh
假设 JBoss 根目录为 ${JBOSS_HOME}
删除插件安装目录 ${JBOSS_HOME}/rasp
如果是 JBoss4 ~ Jboss6:
Linux下打开 ${JBOSS_HOME}/bin/run.sh
假设Resin根目录为${RESIN_HOME}
删除插件安装目录 ${resin_HOME}/rasp
如果是 resin3:
Linux下打开 ${RESIN_HOME}/conf/resin.conf
假设 Wildfly 根目录为 ${JBOSS_HOME}
删除插件安装目录 ${JBOSS_HOME}/rasp
找到启动配置文件:
Linux下打开 ${JBOSS_HOME}/bin/standalone.sh
假设Jetty根目录为${JETTY_HOME}
删除插件安装目录 ${JETTY_HOME}/rasp
修改服务器启动参数,删除 javaagent、Dlog4j.rasp.configuration 参数
重启 Jetty 服务器
假设Websphere的根目录为 ${WEBSPHERE_HOME}。首先删除 OpenRASP 相关文件 ${WEBSPHERE_HOME}/rasp,然后参考下面的步骤删除 JVM 启动参数。
打开 WebSphere 控制台,
在左边的导航栏选择,服务器 > 服务器类型 > WebSphere Application Server
点击 server1 服务器进入服务器的管理界面(或者你的服务器)
找到,服务器基础架构 >java和进程管理 > 进程定义,点击进入
点击右侧 Java虚拟机 选项
找到 通用JVM参数,将其删除,保存修改
最后重启 WebSphere 服务器生效
假设Spring Boot根目录为${SPRING_BOOT_HOME}
删除插件安装目录 ${SPRING_BOOT_HOME}/rasp
修改服务器启动参数,删除 javaagent、Dlog4j.rasp.configuration 参数
重启 Spring Boot 服务器
找到 php.ini 配置文件,删除 extension=openrasp.so,以及所有 openrasp. 开头的配置选项,e.g
然后重新加载PHP服务器生效,e.g
对于PHP-FPM服务器,可尝试 service php5.6-fpm reload
对于Apache PHP模块,可尝试 service apache2 reload
最后在 phpinfo() 里确认,如果看不到 openrasp 模块信息,则表示卸载成功
-
deny
禁止网站被 frame/iframe 嵌套
sameorigin
允许网站被 frame/iframe 嵌套,但父页面只能是当前域
不开启
-
nosniff
如果从script或stylesheet读入的文件的MIME类型与指定MIME类型不匹配,不要读取该文件。可用于防止XSS等跨站脚本攻击。
不开启
-
1; mode=block
开启浏览器的 XssAuditor 功能
不开启
-
noopen
IE 8以上版本的用户,不打开文件而直接保存文件。在下载对话框中不显示 "打开" 选项。
本章节讲解 OpenRASP 提供的一系列接口
若有新的接口需求,你可以去 Github 提交 Issue
${CATALINA_HOME}/bin/catalina.bat搜索关键词 javaagent 与 Dlog4j.rasp.configuration,删除或注释掉相应行
重启 tomcat 服务器
${JBOSS_HOME}/bin/run.bat如果是 JBoss7:
Linux下打开 ${JBOSS_HOME}/bin/standalone.sh
Windows下打开 ${JBOSS_HOME}/bin/standalone.bat
把如上文件按照手动安装文档恢复原样
重启 JBoss 服务器
${RESIN_HOME}/conf/resin.conf如果是 resin4:
Linux下打开 ${RESIN_HOME}/conf/cluster-default.xml
Windows下打开 ${RESIN_HOME}/conf/cluster-default.xml
把如上文件按照手动安装文档恢复原样
重启服务器
${JBOSS_HOME}/bin/standalone.bat把如上文件按照手动安装文档恢复原样
重启 Wildfly 服务器






200响应是动态生成的,比如 JSP 文件或者 Servlet
inject.urlprefix 配置选项不为空
要注入的内容,aka <app_home>/rasp/assets/inject.html 存在且内容不为空
另外,如果你使用的是自动化安装包,我们在默认生成的 openrasp.yml 配置文件里,禁用了这个功能
你需要手动注释掉 hooks.ignore 这一行,才能开启这个功能
你需要配置 inject.urlprefix 选项,设置要匹配的URL前缀,e.g http://www.baidu.com/admin/
编辑 <app_home>/rasp/assets/inject.html 文件,输入你要插入的内容,e.g
OpenRASP 会监控这个文件,保存后立刻生效
删除 <app_home>/rasp/assets/inject.html 文件,删除后立即生效
访问一个 JSP 或者 Servlet 页面,检查注入的内容是否存在即可。
注意: 浏览器可能有缓存,建议清掉缓存测试
如果你是在 VMWare 虚拟机里测试 OpenRASP,然后插件是放在 VMWare 共享 里的,这个时候 inotify 可能不会生效,也就无法实时更新 js 脚本。
这可能是因为 vmhgfs 跟 inotify 本身存在兼容性问题。最快的解决方法,就是将整个服务器软件都复制到虚拟机的磁盘上,比如 /root/tomcat/
java -jar RaspInstall.jar -uninstall <app_home># <server_pid> 为服务器进程 id
# $JAVA_HOME 为 jdk 根目录环境变量,如果未指定该环境变量,替换为 jdk 的完整根目录
java -Xbootclasspath/a:$JAVA_HOME/lib/tools.jar -jar RaspInstall.jar -uninstall <app_home> -pid <server_pid># <server_pid> 为服务器进程 id
java -jar RaspInstall.jar -uninstall <app_home> -pid <server_pid>php uninstall.php -d <openrasp_rootdir>extension=openrasp.so
openrasp.root_dir=/opt/rasp
...<!-- Added by OpenRASP -->
<script type="text/javascript">
alert('Hello from OpenRASP - https://rasp.baidu.com');
</script>
<!-- End added by OpenRASP -->hooks.ignore: http_output<!-- Added by OpenRASP -->
<script type="text/javascript">
alert('Hello from OpenRASP - https://rasp.baidu.com');
</script>
<!-- End added by OpenRASP -->所有插件需要实例化一个 RASP 对象,并在此对象上注册各检测点对应的检测程序
创建 RASP 实例需传入插件名,e.g demo
支持发送 GET/POST 请求,其中 data 字段可以是字符串、对象或者 Buffer
检测函数接受两个参数
params 对应检测点的参数信息
context 请求上下文信息
具体有哪些检测点可以注册,以及 params 的样例,请参考检
注意: 对于同一个检测点,如果你注册了多个检测函数,这些函数会按照注册顺序,依次调用
函数接受两个参数
query 表示要解析的查询语句
server 表示SQL服务器类型
目前本功能还在试验阶段,且暂时不区分SQL服务器类型。
函数接受一个参数
command 表示要解析的命令
目前本功能还在试验阶段,且暂时不区分操作系统
使用方法与 console.log 一致,只是会同时输出插件的名字,方便你区分不同插件的日志
在编写单元测试时,可手动调用此方法
这个方法会按照注册顺序,依次调用所有的检测函数,并返回一个检测结果数组
e.g 模拟一个SQL注入请求,请调用插件获取检测结果
var plugin = new RASP('demo')action 表示期望的结果,是拦截、日志还是放行;id 是测试用例编号。其他字段主要是对请求上下文的模拟。运行单元测试,需要两个关键参数
测试用例目录
检测插件路径
比如,若要测试官方插件,可以执行如下命令:
当测试结果中出现 failing 和详细错误信息时,表示测试用例没有通过。
每一个测试用例所消耗的时间出现在测试结果行的最末端。
若时间被标注为黄色,表示该测试用例消耗时间过长,若时间被标注为红色,表示该测试用例消耗时间超过最大限制。默认超时时间为 20ms
var name = plugin.get_version()
// 返回 1.2.0var name = plugin.get_jsengine()
// 返回 rhino / v8var body = {
"name": "openrasp"
}
var req = {
"method": "post",
"url": "http://127.0.0.1/test",
"data": data,
"maxRedirects": 0,
"timeout": 30,
"headers": {
"content-type": "application/json"
},
}
RASP.request(req)plugin.register('sql', function(params, context) {
// 在这里实现检测逻辑
// 并返回结果
return {
action: 'ignore',
message: '无风险'
}
})RASP.sql_tokenize('SELECT * FROM users WHERE id = -1 union/*!50000select*/1,2,3', 'mysql')
// [
// { text: 'SELECT', start: 0, stop: 5 },
// { text: '*', start: 7, stop: 7 },
// ...
// ]RASP.cmd_tokenize('/bin/bash -c ls')
// [
// { text: '/bin/bash', stop: 8, start: 0 },
// { text: '-c', stop: 11, start: 10 },
// { text: 'ls', stop: 14, start: 13 }
// ]plugin.log('hello', 'openrasp')
// 将会在日志里输出 [demo] hellp openraspvar name = plugin.name
// => 'demo'var params = {
'query': 'select * from users',
'server': 'mysql'
}
var checkContext = new Context()
RASP.check('sql', params, context)
// => [{
// 'action': 'block',
// 'message': 'attack',
// 'name': 'demo'
// }]$ rasp check
OpenRASP plugin devtool - https://rasp.baidu.com
Usage: rasp-check
Options:
-d, --case-dir <dir> specify a testcases directory
-p, --plugin-file <plugin> specify a javascript plugin file
-h, --help output usage information [{
"id": "ssrf_userinput_intranet",
"name": "ssrf",
"action": "block",
"params": {
"hostname": "172.16.177.120",
"ip": ["172.16.177.120"],
"url": "http://172.16.177.120/hello.action?redirect=123"
},
"context": {
"parameter": {
"url": ["http://172.16.177.120/hello.action?redirect=123"]
}
},
"description": "SSRF userinput match test"
}]$ rasp check -d ~/openrasp/agent/java/engine/src/test/resources/pluginUnitTest/unitCases/ -p ~/openrasp/plugins/official/plugin.js
[offical] OpenRASP official plugin: Initialized, version 2018-1010-1600
✓ sql.json Simple userinput match test: 9ms
✓ sql.json SQL injection with hex values: 1ms
✓ sql.json SQL injection with datetime methods: 2ms
✓ ssrf.json SSRF userinput match test: 2ms
✓ ssrf.json SSRF false positive test: 1ms
5 passing (26ms)Java 版本: <app_home>/rasp/conf/openrasp.yml
若配置修改后没有生效,请检查日志里是否有 yaml语法错误异常
PHP日志: rasp.log 以及error_log ini配置的文件名
Java日志: rasp.log
plugin.timeout.millis
对于单个检测算法, JS 插件超时时间 (毫秒)
100
plugin.maxstack
插件获取堆栈的最大深度
100
plugin.filter
针对文件访问hook点,是否开启过滤机制。 若开启,当目标文件不存在,将不进入检测插件。 支持 directory, readFile, rename, include 四个 hook 点
true
body.maxbytes
最多读取 POST body 的前多少字节
4096
log.maxstack
报警日志记录的最大堆栈深度(v1.2开始废弃)
50
log.maxburst
每个进程/线程每分钟最大日志条数
100
log.maxbackup
日志最大备份天数
30
syslog.facility 的值请参考 What are Syslog Facilities and Levels,比如 7 表示 news 类型。另外,由于报警日志大小超过 1KB,所以我们仅支持 TCP 方式推送报警。
syslog.enable
是否开启 syslog
false
syslog.url
服务器地址,如 tcp://ip:port
(空)
syslog.tag
tag 值
OpenRASP
syslog.facility
facility 值
1
block.status_code
拦截攻击后,将状态码设置为这个值
302
block.redirect_url
拦截攻击后,跳转到这个URL,并根据模板设置 request_id 参数
https://rasp.baidu.com/blocked/?request_id=%request_id%
block.content_json
拦截攻击后,若期望响应类型为JSON,则根据此模板显示内容
{"error":true, "reason": "Request blocked by OpenRASP", "request_id": "%request_id%"}
block.content_xml
拦截攻击后,若期望响应类型为XML,则根据此模板显示内容
<?xml version="1.0"?> <doc> <error>true</error> <reason>Request blocked by OpenRASP</reason><request_id>%request_id%</request_id> </doc>
注意: 目前仅 Java 服务器支持熔断,PHP 暂不支持
cpu.usage.enable
是否开启熔断支持
false
cpu.usage.interval
每隔多少秒采集一次CPU占用率 配置范围是 1-1800
5
cpu.usage.percent
当单核CPU占用率超过这个数值,关闭所有防护。 配置范围是 30-90
90
dependency_check.enable
是否采集依赖库
true
request.param_encoding
仅Java支持,设置 Form 参数的编码格式。设置后,可在用户解析参数之前按照该编码提前获取用户输入,如 UTF-8
(空)
clientip.header
从指定的 HTTP header 里获取客户端真实IP,并记录到报警日志的 client_ip 字段里。注意: 本配置区分大小写。
ClientIP
inject.urlprefix
对于以下URL,修改响应并注入HTML
(空)
以下配置无法云端下发,需要放在 php.ini 里,修改后重启PHP服务器生效。
openrasp.root_dir
openrasp 根目录,存放插件、日志
(空)
openrasp.locale
配置的语言类型
(空)
openrasp.heartbeat_interval
心跳间隔,单位秒
180
openrasp.backend_url
云控后台 URL 地址
(空)
单机版文件监控相关设置,监控范围是配置文件以及插件目录 (要求客户端版本 >= 1.3.6)
file_monitor.mode
单机版文件目录监控机制,重启生效。 jnotify: 使用 jnotify 监控目录变更 scan: 定期扫描目录变更 disable: 关闭插件更新机制
scan
file_monitor.interval
在定期扫描模式下,多久扫描一次目录(秒)
3
以下配置虽然还是在 openrasp.yml 里,但是无法云端下发,且修改后需要重启服务器生效。
cloud.backend_url
云控后台 URL 地址
(空)
cloud.app_id
云控通信使用的 app_id 值
(空)
cloud.app_secret
云控通信使用的 app_secret 值
(空)
cloud.enable
是否开启远程管理功能
false
其中 http_output 为HTML注入功能,其他的都比较好理解。修改后需要重启 Java 应用服务器。
hooks.ignore=sql,sqlPrepared,directory,request,readFile,writeFile,fileUpload,command,xxe,ognl,deserialization,include,ssrf,http_output,webdav,sqlSlowQuery,rename,dubboRequest
若要禁用所有 hook 点,可直接使用 hooks.ignore=all 配置。
当在标准输出或者插件日志里看到如下内容时候,可以考虑提高内存占用:
[libopenrasp_v8_java.so+0xb4f142] v8::base::OS::Abort()+0x12
Allocation failed - JavaScript heap out of memory
e.g 将老生代内存设置为20MB,新生代2MB:
对于 Tomcat 这样具有启动脚本的服务器,在启动脚本最前面加上即可
对于 SpringBoot 这样直接使用 java 命令启动的服务器,在启动之前设置下环境变量即可
注意: 设置后需要重启 Java、PHP 进程生效。
Context 类包含当前请求信息和服务器信息
绝对路径,不包含 Query String
返回URL参数
字母为小写
获取当前请求的 headers,其中key的名字均为小写。这个值可能为空,使用前需要判断,e.g if (context.header != null)
仅返回请求体原始数据的前4KB,类型为
因受到服务器限制,插件系统不保证一定能够获取到请求体原始数据。在Java应用下面,只有应用读取了body,插件才能获取到。因此在 request hook 点是拿不到 body 的。
获取当前请求的 POST JSON 参数
对于 java 服务器,当用户已经获取过请求参数的情况下, 我们会返回 ServletRequest.getParameterMap() 的结果,也就是 Map<String, String[]>
当用户还没有获取过任何参数, 我们会返回空对象, 这样做既可以保证用户在获取参数的时候不会产生乱码, 同时在插件中做用户参数匹配检测过程中也可以降低误报率。若要在 request hook 点获取到用户输入,请参考 文档,设置 request.param_encoding 参数。
这个参数只是应用服务器看到的请求来源IP。如果是反向代理部署方式,你可能需要获取 X-Forwarded-For、X-Client-IP 等HTTP响应头数据
当前服务器的属性,包括服务器类型、开发语言等等
若要判定是否为 Windows 系统,可使用 context.server.os.indexOf('Windows') == 0
对于java服务器,返回 webapps 目录;对于php服务器,返回 webroot
在编写单元测试时,若要同时模拟请求信息,可以通过自定义 Context 实例的方式来实现,e.g
当然,除了请求方法以外,你可还可以自定义其他参数,
如果没有定义某个方法,这个方法将返回 undefined
export OPENRASP_V8_OPTIONS="--max-old-space-size=20 --max-semi-space-size=2"#!/bin/sh
export OPENRASP_V8_OPTIONS="--max-old-space-size=20 --max-semi-space-size=2"
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.export OPENRASP_V8_OPTIONS="--max-old-space-size=20 --max-semi-space-size=2"
java -jar XXX.jar [其他参数]context.path
// => '/my/article.jsp'lru.maxsize
插件检测结果为ignore时,我们会缓存检测结果。 再次遇到相同的行为参数,将不会进行检测。 LRU只对数据库、文件操作生效,所有检测点共享一个LRU。
1024
ognl.expression.minlength
为了减少OGNL检测的性能损耗, 当OGNL语句达到这个长度才调用插件
30
syslog.connection_timeout
连接超时时间 (毫秒)
50
syslog.read_timeout
读超时时间 (毫秒)
10
syslog.reconnect_interval
重连时间间隔 (秒)
300
block.content.html
拦截攻击后,若期望响应类型为其他情况,则根据此模板显示内容
</script><script> location.href= "https://rasp.baidu.com/blocked2/?request_id=%request_id%" </script>
debug.level
debug 等级,0为关闭 debug 模式
0
decompile.enable
是否开启反汇编功能。 开启后可获取源代码,但是会非常消耗性能
0
offline_hosts.cleanup.interval
清理离线时间间隔超过几天以上的主机。1以上的值表示开启
0
openrasp.app_id
云控通信使用的 app_id 值
(空)
openrasp.rasp_id
自定义的 RASP ID,如果空就计算一个
(空)
openrasp.app_secret
云控通信使用的 app_secret 值
(空)
openrasp.remote_management_enable
是否开启远程管理功能
false
cloud.heartbeat_interval
心跳间隔,单位秒
180
hooks.ignore
默认开启全部 hook 点,有不需要的可在这里关闭,逗号分隔
(空)
rasp.id
自定义的 RASP ID,如果空就计算一个
(空)
context.querystring
// => 'offset=10&size=10'context.method
// => 'get'context.protocol
// => 'https'context.header
// => {
// 'user-agent': 'Chrome',
// 'content-type': 'application/json'
// ...
// }context.body
// => ArrayBuffercontext.json
// => {
// 'field': 'Value',
// ...
// }// context.querystring = 'offset=10&size=10'
// context.body = 'filter=odd'
context.parameter
// => {
// 'offset': ['10'],
// 'size': ['10'],
// 'filter': ['odd']
// }context.remoteAddr
// => '2.3.3.3'context.server
// {
// 'name': 'Tomcat / JBoss / Jetty',
// 'version': '8',
// 'os': 'Linux',
// 'language': 'java / php'
// }context.appBasePath
// => '/home/tomcat/webapps'var context = new Context()
// 自定义 method 参数信息
var context = new Context({
getMethod: function() {
return 'get'
}
})var context = new Context({
getPath: function(){},
getQuerystring: function(){},
getMethod: function(){},
getProtocol: function(){},
getHeader: function(){},
getParameter: function(){},
getBody: function(){},
getRemoteAddr: function(){},
getServer: function(){}
})在SQL注入的探测阶段,或者报错注入的攻击阶段,通常会在数据库产生大量的异常。因此,通过监控异常可以有效的发现的SQL注入攻击。目前我们所有支持的数据库均可以监控SQL异常,且异常代码可以在插件里配置。
插件里默认监控的SQL异常如下,具体请参考官方插件的 sql_exception 检测算法。
当MySQL服务器与JDBC驱动不兼容,我们将无法从异常消息里提取SQL错误代码,并打印这个错误。比如 JDBC 5.1.46 + MySQL 5.5 就会出现这个问题,可以考虑升级JDBC驱动到对应的版本来解决。
这个错误会让数据库异常监控失效。
本列表还在不断更新中,如果你有任何疑问,请联系我们。
大部分漏洞环境都可以在 baidu-security/app-env-docker - 基于 Docker 的真实应用测试环境 找到,如果你需要进行测试,参考上面的文档操作即可。
Struts OGNL 系列
Spring 系列
反序列化系列
任意文件下载
任意代码执行
未分类
任意文件上传
SQLi
任意文件写入 - 需要开启 writeFile_script 算法
任意文件包含
任意文件下载
目录遍历漏洞
代码执行
反序列化
SSRF
待添加
待添加
待添加
1060
Duplicate column name '5.5.60-0ubuntu0.14.04.1'
1062
Duplicate entry '::root@localhost::1' for key 'group_key'
1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ') from mysql.user' at line 1
1105
XPATH syntax error: 'root@localhost'
1367
Illegal non geometric 'user()' value found during parsing
42601
normal syntax error
22P02
ERROR: invalid input syntax for type double precision: "DATABASE: test1"
1
generic error, like syntax error、malformed MATCH expression: ["3.6.23.1] and other
ORA-01740
missing double quote in identifier
ORA-01756
quoted string not properly terminated
ORA-00907
missing right parenthesis
-5583
malformed quoted identifier
-5590
unexpected end of statement
105
Unclosed quotation mark after the character string '%.*ls'.
245
Conversion failed when converting the %ls value '%.*ls' to data type %ls.
42603
The string constant beginning with "'xxx" does not have an ending string
OpenRASP 大部分的安全检测逻辑都是在插件中实现的,可以在多个平台复用。当引擎检测到敏感行为时,会依次调用插件进行检测,如果某个插件认为此操作存在风险,可返回 拦截,我们便会阻断这个操作,同时不再调用后续插件进行检测。
目前,OpenRASP 支持对数据库、文件、网络等行为进行检测,本章节讲解如何编写一个插件。
绿盟科技博客
Seebug
下载 999-event-logger.js 这个插件并安装到插件目录。
这个插件会把所有的参数打印出来,通常是 <app_home>/rasp/logs/plugin/plugin-DATE.log,e.g
注意: 从 1.0 RC1 开始,我们默认开启了检测结果LRU。当插件检测结果为 ignore,在插件更新之前,相同的插件参数将不会再次检测。在这种情况下,event-logger 将不会打印调试日志。
2017-10-13 17:10:05,254 INFO [http-bio-8080-exec-3][com.baidu.openrasp.plugin.log]
ReferenceError: "abc" is not defined.
at official.js:407 (test)
at official.js:412 (anonymous)2018-07-25T16:28:14+08:00 [event-logger] 999-event-logger: 初始化成功
2018-07-25T16:28:19+08:00 [event-logger] 读取文件: /etc/hosts通过文件函数写入 WebShell,OpenRASP 不会拦截?{#case-file-write}
我们发现,有的业务需要能够写 PHP 脚本,e.g
由于这类情况较多,官方插件已经默认不再拦截写 PHP/JSP 等脚本文件的操作。如果你没有这样的业务,可以在管理后台定位到 系统设置 -> 防护设置 -> 任意文件写入,并将 拦截所有 php/jsp 等脚本文件的写入操作 改为拦截攻击或者记录日志即可。
我使用 WebShell 查看了一些系统目录,OpenRASP 不会拦截?{#case-dir}
理论上,web 应用不应该访问 webroot 之外的文件。但在实际情况中,我们发现了很多例外:
某OA厂商反馈,他们的 tomcat 应用会读取 ../../../../license.dat,会造成误报
PHP Larvael 框架,需要包含 webroot 同级目录的框架文件
为了兼容这些情况,我们在 directory_outsideWebroot、include_outsideWebroot 等几个算法里都增加了判断,只有当请求参数里包含跨目录,且跳出了 webroot,我们才会判定为漏洞,比如:
当然,如果你想快速解决这个问题,可以通过增加文件目录探针来解决。即定位到 forcefulBrowsing,修改探针列表:
当应用访问了这些敏感文件或者目录,我们就会打印报警或者拦截请求。
我的SQL语句里包含 chr(10) 调用,导致被拦截
在SQL注入阶段,自动化利用工具通常会大量使用 chr 函数来实现盲注攻击。因此,OpenRASP对SQL语句进行了检查,默认情况下如果 chr 函数调用超过5次,就会判定为攻击。
若要关闭这个检测算法,请打开官方插件,定位到如下内容:
删除 chr 这一行后,重新在后台上传并下推插件即可。
我在使用 phpMyAdmin 的时候,操作被 OpenRASP 拦截
URL白名单是一个比较好的解决方式,目前可以通过修改检测插件的方式来实现。请参考 管理后台 - 添加白名单 进行配置。
在某些情况下,你还需要重启PHP服务器生效。
我在应用内部,使用 ../../ 读取web目录外面的文件,OpenRASP不会拦截?
有一些OA厂商,在Windows下面会使用类似 ../../../license/license.dat 来读取文件,所以单纯看应用是否用 ../ 来读取其他目录的文件,是会产生误报的。所以我们默认关闭了 readFile_outsideWebroot 算法。
如果你没有这样的需求,可以打开这个算法。
支付回调接口,测试环境下SSRF误报?
SSRF 常见的特征为,访问的URL来自用户输入,且域名指向内网地址。比如,
按照这个思路,我们实现了 ssrf_intranet 检测算法。但是在某些测试环境下,这个算法会产生误报。
支付类的接口,当支付完成,通常会调用回调接口以通知支付是否成功。在测试环境,回调接口通常是内网地址,就造成了 ssrf_intranet 算法的误报。当然,线上的回调接口都是公网地址,不会有这个问题。
OpenRASP 支持XSS检测吗?
支持,是通过检查页面结构是否被用户输入所改变来实现的。
官方插件无法拦截攻击,我应该如何调试
有的时候,你会发现官方插件无法拦截攻击,你可以参考 999-event-logger.js 这个插件,将插件收到的内容打印出来,并观察官方插件的检测算法是不是不够完善?
有问题请到QQ群里反馈,我们会尽快解决。
wp_config.php - wordpress 安装时需要写配置文件,如果是安装好的可忽略
201704_cplog.php - discuz 错误日志,经常更新
runtime/cache/ - thinkphp 框架页面缓存
...GET /download.php?file=./../..///././../../etc/resolv.confvar forcefulBrowsing = {
...
// 目录探针 - webshell 查看频次最高的目录
unwantedDirectory: [
],
// 文件探针 - webshell 查看频次最高的文件
absolutePaths: [
]
...
} function_count: {
chr: 5,
char: 5
}GET /ssrf.php?url=http://test.baidu.comIAST(交互式扫描)技术是一种实时动态交互的漏洞检测技术,通过在服务端部署agent程序,收集、监控Web应用程序运行时函数执行、数据传输,并与扫描器端进行实时交互,高效、准确的识别安全缺陷及漏洞。目前OpenRASP项目已实现相当于IAST agent端的OpenRASP agent,在此基础上引入一个扫描端,即可实现一个完整的IAST扫描工具。
灰盒扫描工具采用Python3实现,数据库采用MySQL,通讯采用HTTP+JSON的方式。整体架构图如下: 工具分为扫描器端和agent端,Agent端用于收集web应用的运行信息,扫描器端用于处理插件产生的请求信息,并完成整个IAST扫描逻辑
由一个单独的OpenRASP插件构成,用于提取http请求中hook点产生的信息,并通过HTTP协议以JSON形式发送至扫描器端。
该部分是一个独立运行的扫描工具,借助从OpenRASP插件部分获取的信息完成扫描任务。
功能设计和模块划分
扫描模块包括三个模块:预处理模块(Preprocessor)、扫描模块(Scanner)、监控模块(Monitor)
预处理模块即图中HTTPServer部分,用于接收agent插件的http请求,处理、存储、分发http请求信息
扫描模块用于运行扫描插件,执行漏洞扫描逻辑
监控模块用于定期获取其他模块的运行时信息,调整参数,提供控制台的HTTP服务等
运行流程示例
一个典型扫描流程,以SQL注入的扫描过程为例:
在安装了python3.7的环境中可以直接运行IAST
运行参数与pip安装相同
所有扫描插件均位于plugin/scanner目录下,所有扩展名为.py的文件都会在启动扫描器时被加载,ScanPluginBase.py为插件基础类,提供编写插件所需的一系列接口,具体参考
这里以编写一个简单的sql注入fuzz插件为例,介绍插件的编写方法:
首先在plugin/scanner目录下新建一个new_plugin.py文件,粘贴以下内容:
在plugin_info中填写插件基本信息:
实现mutant函数,生成扫描向量
每个被发送并获取结果的请求序列都会回调check函数,在check函数中来实现漏洞判定:
如果自行实现检测函数,需要在检测到漏洞时,使用set_vuln_hook标记有漏洞的hook点信息:
需要注意的是,扫描模块是基于asyncio实现的异步扫描,每个插件会以一个coroutine的形式运行,因此应避免在插件中使用同步的io操作以免影响扫描性能。在进行异常捕获时,如果要捕获全部异常,应单独处理asyncio.CancelledError异常,以免扫描任务无法被终止:
所有扫描插件均位于plugin/deduplicate目录下,IAST启动时会加载core/config.py中指定的去重插件,去重插件是为了避免同一个请求被反复扫描,应当根据扫描目标的url结构、参数等特性来编写,DedupPluginBase.py为插件基础类,提供编写插件所需的一系列接口,具体参考
编写一个去重插件
在plugin/deduplicate目录下新建一个new_plugin.py文件,写入以下内容:
去重插件只需要实现一个get_hash方法即可,该方法传入当前待去重请求对应的raspResult类的实例,返回一个hash字符串,返回hash相同的请求会被视为重复请求,这里直接调用了默认的get_hash_default方法,其具体实现如下:
注意:如果插件运行中抛出异常,会自动调用get_hash_default函数生成默认的hash
java 版本使用 javaagent 机制来实现。在服务器启动时,可动态的修改Java字节码,对敏感操作的函数进行挂钩,比如:
数据库操作
文件读取、写入操作
命令执行
...
当服务器发生攻击,就会触发这些Hook点,此时RASP agent就可以获取到函数的参数,比如要读取的文件名、要执行的命令等等。
启动时首先会进入 javaagent 的 premain 函数,该函数会在 main 函数之前预先执行,
当去 hook 像 java.io.File 这样由 BootstrapClassLoader 加载的类的时候,无法从该类调用非 BootstrapClassLoader 加载的类中的接口,所以 agent.jar 会先将自己添加到 BootstrapClassLoader 的ClassPath下,这样 hook 由 BootstrapClassLoader 加载的类的时候就能够成功调用到 agent.jar 中的检测入口
因为启动时候进行了插桩操作,当有类被 ClassLoader 加载时候,所以会把该类的字节码先交给自定义的 Transformer 处理
自定义 Transformer 会判断该类是否为需要 hook 的类,如果是会将该类交给 javassist 字节码处理框架进行处理,
javassist 框架会将类的字节码依照事件驱动模型逐步解析每个方法,当触发了我们需要 hook 的方法,我们会在方法的开头或者结尾插入进入检测函数的字节码
把 hook 好的字节码返回给 transformer 从而载入虚拟机
启动时架构如下图所示:
我们以 tomcat + JDBC + MySQL 为例,简单说明下请求处理的流程
服务器收到一个请求,从而进入了服务器的请求 hook 点(该 hook 点每个服务器不一样,具体参照源码),该 hook 点标注当前线程为请求线程,开启当前线程的检测开关并把请求对象和响应对象进行缓存,以便后面使用
服务器发起SQL查询
进入 SQLStatementHook 点,我们挂钩了 execute、executeUpdate、executeQuery 等方法,从该方法进入检测流程如下:
判断当前线程是否为请求线程(第一步标记的),如果是继续下面检测
OpenRASP 中JS引擎执行架构如下图所示:
我们以 tomcat 启动为例,说明基线检测流程
进入了基线检测关键函数(tomcat 启动函数)
进入本地基线检测插件(注:基线检测不进入js插件检测),检测当前环境的关键参数(http-only是否开启,是否为root启动等)
根据检测结果决定是否拦截,不拦截的情况下只打印日志到 logs/policy_alarm.log
检测架构如下图所示:
本章节讲解如何编译 OpenRASP,具体内容请参考子章节。
log4j 日志配置文件,如果存在则跳过根据 openrasp.yml 文件初始化相应配置项
初始化 JS 插件模块
JS 上下文类初始化
插件文件初始化
初始化字节码转换模块
给 load class 操作进行插桩操作,当类加载的时候会先进入 agent 进行处理
对于在初始化前已加载的类执行 retransform 处理,e.g FileInputStream
输出启动成功日志,开启全局 Hook 开关(启动阶段为关闭状态)
若启动过程中发生错误,记录错误日志
给 openrasp.yml 配置文件和 js 插件目录以及 assets 目录增加文件监控,以便文件内容更改的时候不需要重启就能够实时生效
采集 connection_id(这个字段仅JDBC支持)、SQL 语句以及数据库类型 等信息
构建参数信息,调用本地插件和 JS 插件进行安全检测,JS 插件由 Rhino 引擎执行,Rhino 引擎执行是 mozilla 为 java 提供的 JavaScript引擎,该引擎会将 JS 代码编译为 java 的 class 字节码在 JVM 中运行,Rhino 引擎文档
根据插件的执行结果决定是拦截请求、放行还是仅打印日志
进入 SQLResultSetHook 点,我们挂钩了 resultSet.next 方法
调用本地插件检查是否发生拖库行为,默认策略为一次查询结果超过500条就报警
若决定拦截攻击
输出报警日志到 logs/alarm.log
如果header还没有发出,默认使用 302 跳转到拦截页面
如果body还没有发出,则重置未发送的body
输出自定义拦截页面跳转js脚本
</script><script>location.href='.../?request_id=xxx'</script>



OpenRASP 采用模块化的结构,按照初始化顺序,启动流程如下:
初始化OpenRASP所需全局变量
注册INI配置条目,通过ini配置文件初始化全局配置
日志模块,记录报警、插件、基线等日志,支持FILE/TCP/UDP
V8模块,JS运行环境,负责插件加载与结合运行时上下文的检测能力
HOOK模块,敏感PHP_FUNCTION挂钩执行检测及检测结果处理
INJECT模块,针对特定URL,修改响应内容,注入HTML
安全基线检查模块,检查敏感ini配置项
文件监控模块,监控插件目录,实现运行时检测逻辑修改
下面针对几个主要的模块进行针对性说明:
日志模块启动流程如下:
初始化日志模块所需全局变量
申请共享内存(针对特定SAPI),用于部分日志的进/线程间同步
获取本机网卡以及主机信息,用于基线日志记录
我们将 V8 嵌入到 OpenRASP 中作为 JavaScript 插件的执行引擎
MINIT 阶段载入所有插件,生成一份 V8 Startup Snapshot
请求处理线程第一次触发检测时,使用 V8 Startup Snapshot 还原此线程独享的 V8 Isolate
每个请求线程在对应的 V8 Isolate 环境上执行检测逻辑
执行检测逻辑前向 V8 Platform 添加超时监控后台任务,超时后中断检测
GSHUTDOWN 阶段销毁线程对应 V8 Isolate
HOOK流程包含两类:compiler_globals的handler替换和用户自定义opcode_handler,启动流程如下
在全局compiler_globals对应的hashtable(function_table和class_table)中查找非禁用函数对应zend_function
封装原有handler,根据需求增加前置、后置处理
针对指定opcode(如ZEND_INCLUDE_OR_EVAL)通过zend_set_user_opcode_handler自定义处理逻辑
我们使用经过我们优化增强的 libfswatch 实现了跨平台的文件监控
MINIT 阶段初始化 fswatch 实例,并开启后台线程进行目标文件目录监控
目标文件目录发生变化时,根据类型,向支持重载的 SAPI 主线程发送重载信号
MSHUTDOWN 阶段停止目标文件目录监控,销毁 fswatch 实例和后台线程
经过对比,我们最终选择了 Double Array Trie 算法来匹配白名单,具体实现如下:
白名单存储。白名单放在共享内存里,当云端下发新的配置,通过读写锁更新
白名单匹配。使用 Double Array Trie 算法在白名单里寻找匹配的项目,并生成检测类型的 bitmask。当进入检测点,根据 bitmask 来决定是否直接放行。
内存消耗。每个检测类型最多允许10条白名单,URL长度最大200。最坏情况下,PHP 版本内存 400 KB。
为了适配百度内部的ORP平台,我们特意实现了扩展进程管理模型,以避免再安装一个独立的agent。
在扩展初始化阶段,我们会 fork 出三个进程,分别用于异步日志发送、远程管理、进程守护等功能;在 PHP-FPM 或者 apache 退出或者重启时,我们会杀死这些进程。具体请参考我们的代码实现。
以PHP(mysqli) + MySQL为例,简要说明请求处理的流程,即 RINIT - RSHUTDOWN 阶段:
为新请求计算唯一的request-id,设置response header
初始化不同logger,收集日志相关请求信息
连接数据库,触发 mysqli_connect HOOK点:enforce_policy为1时,若用高权限用户连接数据库,记录基线日志,中断当前请求;enforce_policy为0时,仅当成功连接数据库后检查是否为高权限用户,若是记录日基线志,并将连接信息存入共享内存防止其他进/线程重复报警
数据库语句检测,即mysqli_query HOOK点pre检测,收集查询参数调用V8模块执行检测,具体流程如下:
(待添加)
慢查询检测。即mysqli_query HOOK点post检测,通过 call_user_function 检测查询结果数目,超过 openrasp.slowquery_min_rows 配置项则报警
RSHUTDOWN阶段:释放请求相关资源,根据 openrasp.inject_urlprefix 配置判断是否注入用户自定义HTML

2、测试人员发送了一条HTTP请求到web server,产生请求及其对应的HOOK信息被OpenRASP插件获取,发送至http_server
3、http_server发现请求不是扫描器发出的,对其进行去重后写入数据库
4、扫描模块从数据库获取一条HOOK信息,下发到所有扫描插件
5、sql注入扫描插件分析HOOK信息发现用户输入参数拼接进了sql查询,运行对应扫描逻辑
6、扫描插件生成扫描请求,把原始请求进入query的输入参数替换为单引号
7、扫描插件在请求头添加用于识别扫描请求的scan_request_id,发送扫描请求给web server
10、web server处理请求并返回结果,扫描插件获得http response,同时OpenRASP插件获取到请求hook信息,发送至http_server
11、http_server发现请求是扫描器发出的,将其写入rasp_result_queue队列
12、扫描模块读取rasp_result_queue队列,将rasp_result传给对应的扫描插件
13、扫描插件检查收到的hook信息,发现query逻辑被改变,认为存在SQL注入,将漏洞信息写入数据库

如果你对 docker、Makefile 很熟悉,也可以使用我们的自动化编译环境 - baidu-security/app-env-docker,编译所有的版本,e.g
最终生成的文件在 /tmp/ 下面
# 使用 JDK6 + maven 3.2.3 编译 Java agent
make -C src/openrasp-buildenv compile_java
# 使用 CentOS 6 + gcc 4.9 编译 PHP agent 5.3~5.6, 7.0-7.2 等多个版本
make -C src/openrasp-buildenv compile_php
# 使用 CentOS 6 + go + nodejs 编译管理后台
make -C src/openrasp-buildenv compile_panel
# 执行上面所有步骤
make -C src/openrasp-buildenv compilegit clone https://github.com/baidu-security/openrasp-iast.git
cd openrasp-iast
python3 openrasp_iast/main.py start -f#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# 导入scanner插件基类
class ScanPlugin(scan_plugin_base.ScanPluginBase):
plugin_info = {
"name": "name",
"show_name": "plugin",
"description": "des"
}
# 用于生成测试向量
def mutant(self, rasp_result_ins):
pass
# 用于检测测试结果
def check(self, request_data_list):
pass
plugin_info = {
"name": "sql_basic", # 插件文件名去除扩展名.py后的部分
"show_name": "SQL注入检测插件", # 插件在后台显示的名称
"description": "基础sql注入漏洞检测插件" # 插件功能描述
}def mutant(self, rasp_result_ins):
# 首先判断是否需要扫描
if not rasp_result_ins.has_hook_type("sql"):
return
payload_list = [("1'openrasp", "1'openrasp"),
("1\"openrasp", "1\"openrasp"),
("`a openrasp", "`a openrasp")]
# 获取所有待测试参数
request_data_ins = self.new_request_data(rasp_result_ins)
test_params = self.mutant_helper.get_params_list(request_data_ins, ["get", "post", "json", "headers", "cookies"])
# 生成测试向量的逻辑,返回必须是一个iterable
for param in test_params:
# 只测试包含sql类型hook的请求
if not request_data_ins.is_param_concat_in_hook("sql", param["value"]):
continue
# 每个测试点(参数)生成一个payload_seq,防止重复报警,含有相同payload_seq的测试请求仅保留产生的第一个报警
payload_seq = self.gen_payload_seq()
for payload in payload_list:
# 基于RaspResult类的实例生成测试请求RequestData类的实例
request_data_ins = self.new_request_data(rasp_result_ins, payload_seq, payload[1])
request_data_ins.set_param(param["type"], param["name"], payload[0])
request_data_list = [request_data_ins]
# 每次迭代返回的应该是一个由RequestData类的实例组成的list, 该list中的每个RequestData实例都会被作为测试请求依次发送
yield request_data_listdef check(self, request_data_list):
# 当前插件每个请求序列仅包含1个请求,取[0]
request_data_ins = request_data_list[0]
# 获取检测特征和请求结果
feature = request_data_ins.get_payload_info()["feature"]
rasp_result_ins = request_data_ins.get_rasp_result()
# 检测是否触发sql注入,直接使用checker检测
if self.checker.check_concat_in_hook(rasp_result_ins, "sql" , feature):
# 存在漏洞,返回漏洞描述字符串
return "sql语句逻辑可被用户输入控制"
else:
# 不存在漏洞,返回None
return Nonefor hook_item in rasp_result_ins.get_hook_info():
if has_vuln(hook_item):
rasp_result_ins.set_vuln_hook(hook_item)import asyncio
try:
# do something...
except asyncio.CancelledError as e:
raise e
except Exception as e:
# do something...#!/usr/bin/env python3
# -*- coding: UTF-8 -*-
# 导入去重插件基类
from plugin.deduplicate import DedupPluginBase
# 插件类必须命名为dedupPlugin,并继承自DedupPluginBase.DedupPluginBase
class dedupPlugin(DedupPluginBase.DedupPluginBase):
# 实现get_hash函数,返回hash字符串
def get_hash(self, rasp_result_ins):
return self.get_hash_default(rasp_result_ins)import hashlib
# 计算urlpath、参数、堆栈等数据的hash,连接后生成结果hash
def get_hash_default(self, rasp_result_ins):
path_str = rasp_result_ins.get_path()
stack_hash = rasp_result_ins.get_all_stack_hash()
param_keys = "".join(rasp_result_ins.get_parameters().keys())
query_keys = "".join(rasp_result_ins.get_query_parameters().keys())
json_struct = rasp_result_ins.get_json_struct()
contact_str = "".join([path_str, stack_hash, param_keys, json_struct, query_keys]).encode("utf-8")
return hashlib.md5(contact_str).hexdigest()如上图所示:
虚线下方为安装了 RASP 的服务器,上方为云控后台,云控后台分为 Agent Server 和 Panel Server,Agent Server 负责和 RASP Agent 通信,Panel Server 负责用户与前端的交互。Agent Server 可以部署多个实例,Panel Server只可以部署一个。
Secrete 认证:RaspAgent和云控后台之间的认证方式采用 appID + secrete私钥 的形式进行认证。
主机注册:在启动阶段,若 RASP Agent 开启远程管理,每隔 5 分钟尝试向 Agent Server 注册一次,直到成功,注册信息将会存入 MongoDB,用于前端展示。
定时心跳:每隔 3 分钟 RASP Agent与云端通信一次,心跳时间可配置。发送心跳时,同时提交本地配置的版本号。若有更新版本的配置或者插件,云端会通过心跳返回新的配置和插件。
报警日志上传:图中绿色箭头为报警日志的上传流向,Agent Server 采集日志有两种可选模式,第一种模式直接将 RASP Agent 上传的日志存入 ES,这种方式在日志量较大的情况下会有日志丢失的情况,第二种是将日志写入文件,然后由 logstash 采集并传入 ES,这种方式较为复杂,但日志不易丢失,不同语言的 RASP 内部日志上传方式如下:
PHP 版本每隔 10s 检查是否有新的日志。若上传成功,会记录文件读取偏移量,并将状态文件落地。
Java 版本使用 Log4j 内置的缓冲区,默认大小是 128 条。若未发送的日志量超过缓冲区大小,最早的日志会被抛弃。
插件与配置升级:用户通过 Panel Server 下发配置和插件到 MongoDB,然后由 RASP Agent 通过与 Agent Server 心跳取走新的配置和插件。
本文档仅适用于基于 glibc2.12 及以上 的 Linux 或 MacOS
对于 Linux 系统,我们要求使用 g++ 5 或者更高版本进行编译。为了保证最大兼容性,我们建议你使用和生产环境相同的环境进行编译。
下面,我们以 CentOS 6 为例,讲解如何编译 OpenRASP PHP 扩展。值得注意的是,CentOS 7 的安装方法、要执行的命令完全一样。
使用如下命令,安装 g++ 5.3.1 以及 xxd 命令
如果你使用的是发行版自带的 PHP 软件,你还需要安装对应的头文件
安装完成后,执行如下命令进入编译环境
安装高版本 cmake
在OpenRASP仓库根目录执行以下命令
进入源代码目录,执行下面的命令即可;如果你的 PHP 是自己编译的,请使用对应路径的 phpize 命令。
如果 make 命令没有出错,可以继续执行 make install 安装。也可以将生成的扩展 modules/openrasp.so 复制到其它机器安装。对于扩展的具体安装方法,请参考
你可以使用 git 命令,也可以直接在 Github 下载 ZIP 包
为了保证最大兼容性,我们建议使用 JDK 6 进行编译
为编译所依赖的JNI模块,需要安装 c++ 编译器和 cmake 生成器
以 CentOS 为例,使用如下命令,安装 g++ 5.3.1
安装完成后,执行如下命令进入编译环境
安装高版本 cmake
以 64位 Linux 系统为例,在OpenRASP仓库根目录执行以下命令
更多平台的编译细节请参考
https://github.com/baidu-security/openrasp-v8/blob/master/.travis.yml
https://github.com/baidu-security/openrasp-v8/tree/master/.travis
方案1 - 使用 IDEA Intellij 进行操作
导入 maven 工程,目录选 agent/java,正常编译即可
方案2 - 使用 mvn 命令编译
进入命令行,
最终生成的 JAR 包在 boot/target 和 engine/target
如果总是出现超时错误,你可以考虑使用阿里云的镜像。
[ERROR] Plugin org.apache.maven.plugins:maven-resources-plugin:3.0.2 or one of its dependencies could not be resolved: Failed to read artifact descriptor for org.apache.maven.plugins:maven-resources-plugin:jar:3.0.2: Could not transfer artifact org.apache.maven.plugins:maven-resources-plugin:pom:3.0.2 from/to central (https://repo.maven.apache.org/maven2): Connect to repo.maven.apache.org:443 [repo.maven.apache.org/151.101.196.215] failed: Operation timed out (Connection timed out) -> [Help 1]
修改方法是编辑 ~/.m2/settings.xml,并填写如下内容
如果你使用 JDK 1.6 编译,可能会遇到如下错误:
[ERROR] Plugin pl.project13.maven:git-commit-id-plugin:2.1.5 or one of its dependencies could not be resolved: Failed to read artifact descriptor for pl.project13.maven:git-commit-id-plugin:jar:2.1.5: Could not transfer artifact pl.project13.maven:git-commit-id-plugin:pom:2.1.5 from/to central (https://repo.maven.apache.org/maven2): Received fatal alert: protocol_version -> [Help 1]
这是一个 https 证书错误,解决方法是替换 maven 仓库地址为 http 版本。可以考虑修改 ~/.m2/settings.xml,并添加如下内容
如果你使用IDE编译,最终可能出现这样的错误:
Failed to find Premain-Class manifest attribute in D:\apache-tomcat-7.0.82\rasp\rasp.jar
这是因为IDE没有修改 META-INF 下面的文件。我们建议你使用 maven 编译,或者直接导入 maven 工程
本文档列出了我们挂钩的函数列表
其中,SQL注入检测点为 execute/executeUpdate/executeQuery/executeBatch/executeBatchInternal/addBatch 方法之一,具体请看我们在github的源代码,这里不在赘述
git clone https://github.com/baidu/openrasp.git
当你需要增加更多的安全检测能力,你可以尝试修改源代码,增加更多的hook点,并为之编写检测插件。
本章节讲解 OpenRASP 内部的一些实现,以及如何进行二次开发
$openrasp_path/agent/java/boot/target/rasp.jar$openrasp_path/agent/java/engine/target/rasp.jar方案3 - 使用 build-java.sh 生成安装包
如果你使用 Linux 进行编译,可以执行源代码目录下面的 build-java.sh 进行编译和打包操作。这个脚本会在源代码根目录,生成 rasp-java.tar.gz 和 rasp-java.zip 两个文件
目前我们只在 Linux 下面进行了测试。Windows 也可以编译,但我们没有测试过,不保证稳定性。软件安装完毕后,请将 go、node、npm 加入到 $PATH 中,方便后面调用。
你可以使用 git 下载源代码,也可以直接在 github 页面下载 zip 压缩包,
直接执行 build-cloud.sh 即可,最终会在源代码根目录生成 rasp-cloud.tar.gz
进入 rasp-vue 目录,执行如下步骤编译打包,
若没有出错,前端的文件将保存 rasp-vue/dist 目录
编译好前端后,进入 cloud/src/rasp-cloud 目录,执行如下命令安装 beego 工具
复制前端文件到本地目录,
之后执行如下命令打包,
生成的文件为 rasp-cloud.tar.gz
如果你的网络存在问题,可以尝试使用国外的代理服务器,e.g
检测插件针对应用的行为进行检测,当应用执行数据库查询、文件读写等操作,OpenRASP 引擎就会调用检测插件,并将相关参数一并传递过来。一个最小的SQL检测插件如下所示:
首先,我们调用 plugin.register 注册了SQL查询的检测函数,并将SQL语句打印到插件日志。其中,
params 为检查点提供的参数,如SQL语句、要读取的文件等等
context 为请求信息,如请求参数,服务器信息等等
然后,我们在回调函数里,调用 plugin.log 打印了SQL查询语句
最后,我们在回调函数里,返回检测结果,即 "放行"
目前我们支持14个检测点,具体请看 参数说明 文档。
我们在 RASP 类里提供了一些接口,可以直接在插件里调用。比如,你可以调用 RASP.sql_tokenize 将SQL语句转化为 token:
详细 JS API 说明请看 接口说明 文档。
现在,我们已经完成了检测插件,下一步是进行测试。测试有两种方法:
若你是初次接触插件开发,我们推荐使用第二种方式,即使用 OpenRASP 单机版调试。具体调试方法请参考上述文档,这里不再赘述。
现在,我们已经能够编写检测插件,并在客户端运行。接下来就是拦截攻击了,在回调函数里,将返回的 action 字段改为 block 即可拦截请求。比如,当SQL语句包含union注入特征,我们想拦截整个请求的话,可以这样写:
在官方插件里,实际的检测算法要复杂的很多,有兴趣可以参考 official.js 的实现。如果不想拦截攻击,只是想记录攻击日志,可将 action 字段设置为 log。
最后, confidence 字段用来标记报警的可信度,官方插件的范围是 90~100,越高报警的可靠性越高。
注意: 当某个插件拦截了攻击,其他插件将不在被调用。
1. 插件支持 ES6 语法吗?{#faq-1}
插件环境可能不支持某些最新的 JavaScript 语法,请使用 openrasjs 进行语法检查
插件不能使用与平台相关的全局对象,只能使用 JavaScript 标准内建对象
插件可以像编写 Node.js 程序一样引入其他模块,然后通过 webpack 或 browserify 等工具打包成一个文件,但是注意不能引入与平台相关的模块,例如: Node.js 的 http 模块
2. 如果检测点没有返回对象,或者返回的对象不合法,会怎么样?{#faq-2}
若检查点没有返回对象,等于 ignore
若检查点返回了对象,但 action 值不存在或者不为 block/log/ignore 之一,等价于 log
当应用接受到请求时,插件可以对请求进行拦截。(注意: PHP Agent 1.1 开始才支持)
这里不会传递任何参数,如果需要获取请求相关信息,请使用 API接口
注意:
对于 PHP 服务器,若实际读取文件以 https://、http://、ftp:// 之一开头,将会调用 服务器端 HTTP 请求 检测点,不会触发 读取文件 检测点
出于性能考虑,OpenRASP 目前只会提供文件名和绝对路径两个参数
注意:
tomcat 等应用服务器,在部署war包时,暂时不会触发这个回调
对于NTFS数据流,e.g abc.php::$DATA,插件看到的 path 可能是 abc.php::$DATA,realpath 可能是 c:\inetpub\wwwroot\abc.php
url 可能是协议(file、http等等),也能是相对路径(/abc/、abc.txt)
支持的文件包含方式如下,
Java - JSTL import 方式
只有 url 里出现了 :// 且不为 / 开头时,我们才会调用插件
PHP - include/require/include_once/require_once 四种方式
当 url 里包含 :// 时,调用插件
如果文件以 .php 或者 .inc 结尾,或者真实路径在 webroot 下面,不会进入插件
其他情况进入插件
具体参数
目前仅支持 MOVE、COPY 两种方法
目前,OpenRASP 支持 org.apache.commons.fileupload 上传组件(SpringMVC、Struts 底层使用)
出于性能考虑,OpenRASP 只会提取文件前 4 KB 的内容,若要获取更多字节,请参考配置文档
当源是文件,且目标不为文件夹(可以不存在)时才会进入插件
目前,PHP不支持XXE检测
注意: 为了减少性能影响,仅当表达式长度超过 30 时才会调用插件。可手动 ognl.expression.minlength 选项来进行调整
支持的请求方式包含如下 (对应 function 字段),
JDK 中的 URL.openConnection 的方式 (url_open_connection)
commons-httpclient 框架请求方式 (commons_http_client)
httpclient 框架请求方式 (http_client)
PHP stream 请求、cURL 请求
支持的请求方式包含如下 (对应 function 字段),
JDK 中的 URL.openConnection 的方式 (url_open_connection)
httpclient 框架请求方式 (http_client)
PHP stream 请求、cURL 请求
目前支持 eval/function 两种函数
目前仅支持 java System.load() 方式
说明
Java 下面如果 body 过大,会多次分段调用
当响应类型包含 image、audio、video 字样,不会进入插件
该检测点不支持拦截
参数
yum install -y centos-release-scl vim-common
yum install -y devtoolset-4-gcc-c++yum install -y php-develscl enable devtoolset-4 bash# 下载并解压到 /tmp,避免与已有 cmake 冲突
curl -L https://github.com/Kitware/CMake/releases/download/v3.15.3/cmake-3.15.3-Linux-x86_64.tar.gz | tar zx -C /tmp
# 增加临时 PATH
export PATH=/tmp/cmake-3.15.3-Linux-x86_64/bin:$PATH# 更新 git submodule
git submodule update --init
# 编译 openrasp-v8
mkdir -p openrasp-v8/build && cd openrasp-v8/build
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_LANGUAGES=php ..
make# 如果之前编译过,清理下临时文件
phpize --clean
# 生成 configure 文件
phpize
# 生成 makefile
./configure --with-openrasp-v8=../../openrasp-v8/ --with-gettext --enable-openrasp-remote-manager
# 编译
makeyum install -y centos-release-scl
yum install -y devtoolset-4-gcc-c++scl enable devtoolset-4 bash# 下载并解压到 /tmp,避免与已有 cmake 冲突
curl -L https://github.com/Kitware/CMake/releases/download/v3.15.3/cmake-3.15.3-Linux-x86_64.tar.gz | tar zx -C /tmp
# 增加临时 PATH
export PATH=/tmp/cmake-3.15.3-Linux-x86_64/bin:$PATH# 更新 git submodule
git submodule update --init
# 编译 openrasp-v8
mkdir -p openrasp-v8/build64 && cd openrasp-v8/build64
cmake -DCMAKE_BUILD_TYPE=RelWithDebInfo -DENABLE_LANGUAGES=java ..
make
# 复制动态链接库到 resources 目录
mkdir -p ../java/src/main/resources/natives/linux_64 && cp java/libopenrasp_v8_java.so $_
# 编译 v8-1.0-SNAPSHOT.jar,安装 v8-1.0-SNAPSHOT.jar 到 maven 本地仓库
cd ../java
mvn installcd <openrasp_path>/agent/java
mvn versions:use-latest-releases -Dincludes=com.baidu.openrasp:sqlparser
mvn clean package<settings xmlns="http://maven.apache.org/SETTINGS/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0
http://maven.apache.org/xsd/settings-1.0.0.xsd">
<localRepository/>
<interactiveMode/>
<usePluginRegistry/>
<offline/>
<pluginGroups/>
<servers/>
<mirrors>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>central</mirrorOf>
<name>阿里云公共仓库</name>
<url>https://maven.aliyun.com/repository/central</url>
</mirror>
<mirror>
<id>repo1</id>
<mirrorOf>central</mirrorOf>
<name>central repo</name>
<url>http://repo1.maven.org/maven2/</url>
</mirror>
<mirror>
<id>aliyunmaven</id>
<mirrorOf>apache snapshots</mirrorOf>
<name>阿里云阿帕奇仓库</name>
<url>https://maven.aliyun.com/repository/apache-snapshots</url>
</mirror>
</mirrors>
<proxies/>
<activeProfiles/>
<profiles>
<profile>
<repositories>
<repository>
<id>aliyunmaven</id>
<name>aliyunmaven</name>
<url>https://maven.aliyun.com/repository/public</url>
<layout>default</layout>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>MavenCentral</id>
<url>http://repo1.maven.org/maven2/</url>
</repository>
<repository>
<id>aliyunmavenApache</id>
<url>https://maven.aliyun.com/repository/apache-snapshots</url>
</repository>
</repositories>
</profile>
</profiles>
</settings><?xml version="1.0"?>
<settings>
<mirrors>
<mirror>
<id>central-no-ssl</id>
<name>Central without ssl</name>
<url>http://repo.maven.apache.org/maven2</url>
<mirrorOf>central</mirrorOf>
</mirror>
</mirrors>
</settings>git clone https://github.com/baidu/openrasp.gitnpm install
npm run buildexport GOPATH=$(pwd)
go get -u github.com/beego/beerm -rf dist
cp -R ../../../rasp-vue/dist .export PATH=$PATH:$GOPATH/bin
bee packexport https_proxy=XXXX
export http_proxy=XXXX
go get -u XXXXnpm install -g openraspconst plugin_version = '2018-1000-1000'
const plugin_name = 'test-plugin'
'use strict'
var plugin = new RASP(plugin_name)
const clean = {
action: 'ignore',
message: 'Looks fine to me',
confidence: 0
}
// BEGIN ALGORITHM CONFIG //
var algorithmConfig = {}
// END ALGORITHM CONFIG //
plugin.register('sql', function (params, context) {
plugin.log('SQL query: ' + params.query)
return clean
})
plugin.log('plugin-demo: plugin loaded')plugin.register('sql', function (params, context) {
plugin.log('SQL tokens ', RASP.sql_tokenize(params.query, params.server))
return clean
})plugin.register('sql', function (params, context) {
plugin.log('SQL tokens ', RASP.sql_tokenize(params.query, params.server))
if (/union.*select.*from.*information_schema/.test(params.query)) {
return {
action: 'block',
message: '拦截SQL查询,因为XXX',
confidence: 90
}
}
return clean
})plugin.register('sql', function(params, context) {
// 实现你的检测逻辑
})type = sql
params = {
"server": "mysql / oracle / pgsql / mssql / sqlite",
"query": "select * from users",
}type = directory
params = {
"path": "/home/servers/tomcat/webapps/mywar/../../../../../../../../../etc/",
"realpath": "/etc/",
"stack": [
"java.lang.ProcessBuilder.start",
"sun.reflect.NativeMethodAccessorImpl.invoke0",
"sun.reflect.NativeMethodAccessorImpl.invoke",
"sun.reflect.DelegatingMethodAccessorImpl.invoke",
...
]
}type = request
params = {}type = readFile
params = {
"path": "/home/servers/tomcat/webapps/mywar/../../../../../../../../../etc/hosts",
"realpath": "/etc/hosts"
}type = writeFile
params = {
"path": "abc.jsp",
"realpath": "/home/tomcat/webapps/ROOT/abc.jsp",
"stack": [
...
]
}type = deleteFile
params = {
"path": "/home/servers/tomcat/webapps/mywar/../../../../../../../../../tmp/testfile",
"realpath": "/tmp/testfile"
}# Java 示例
type = include,
params = {
url: "file:///etc/passwd",
function: "jstl_import",
realpath: "/etc/passwd"
}
# PHP 示例
type = include,
params = {
url: "/home/webroot/footer/../../../../../../../../../etc/passwd",
function: "require_once",
realpath: "/etc/passwd"
}type = webdav,
params = {
"source": "/home/rsync/apache-tomcat-7.0.78/webapps/webdav/1.txt",
"dest": "/home/rsync/apache-tomcat-7.0.78/webapps/webdav/1.jsp"
}type = fileUpload
params = {
"name": "file",
"filename": "a.jsp",
"content": "<% ... %>",
"dest_path": "upload/a.jpg", # v1.2 加入
"dest_realpath": "/home/www/upload/a.jpg" # v1.2 加入
}type = rename,
params = {
"source": "/var/www/html/uploads/hello.txt",
"dest": "/var/www/html/uploads/hello.php"
}type = command,
params = {
"stack": [
"java.lang.ProcessBuilder.start",
"sun.reflect.NativeMethodAccessorImpl.invoke0",
"sun.reflect.NativeMethodAccessorImpl.invoke",
"sun.reflect.DelegatingMethodAccessorImpl.invoke",
...
]
"command": "/bin/sh -c 'whoami; ls; '"
}type = xxe
params = {
"entity": "file:///etc/passwd"
}type = ognl
params = {
"expression": "_memberAccess" //ognl表达式
}type = deserialization
params = {
"clazz": "InvokerTransformer" //被反序列化对象的类型
}type = ssrf
params = {
"url": "http://0x7f.0x0.0x0.0x1:8080/v1/api/get", // http 请求的 url
"hostname": "0x7f.0x0.0x0.0x1" // http 请求的 hostname
"ip": ["1.1.1.1", "2.2.2.2"] // 无法解析则为空;目前只解析 IPv4 地址
"port": "8080", // 未提供端口为空。对于http模式是80,https默认是443的情况,如果没指定也是空
"function": "commons_http_client"
}type = ssrfRedirect
params = {
"url": "http://0x7f.0x0.0x0.0x1:8080/v1/api/get", // 原始请求的 URL
"hostname": "0x7f.0x0.0x0.0x1" // 原始请求的域名
"ip": ["1.1.1.1", "2.2.2.2"] // 原始请求目标 IP
"port": "8080", // 原始请求的端口,未提供端口为空。对于http模式是80,https默认是443的情况,如果没指定也是空
"url2": "http://127.0.0.1:8080/v1/api/get", // 重定向后的 URL
"hostname2": "0x7f.0x0.0x0.0x1" // 重定向后的域名
"ip2": ["1.1.1.1", "2.2.2.2"] // 重定向后目标 IP
"port2": "8080", // 重定向后的端口,说明同上
"function": "commons_http_client"
}type = eval
params = {
"function": "eval",
"code": "gzuncompress(base64_decode(...));"
"stack": [
...
]
}type = loadlibrary
params = {
"function": "System.load",
"path": "\\8.8.8.8\test.dll",
"realpath": "xxxx"
}type = response
params = {
"content_type": "text/html",
"content": "<h1>xxxx</h1>"
}SSRF
org.apache.commons.httpclient.URI.parseUriReference()
org.apache.http.client.methods.HttpRequestBase.setURI()
com.squareup.okhttp3.HttpUrl.parse(String)
com.squareup.okhttp.HttpUrl.parse(String)
sun.net.www.protocol.http.HttpURLConnection.connect()
反序列化
java.io.ObjectInputStream.resolveClass
命令执行
java.lang.UNIXProcess.<init>
java.lang.ProcessImpl.<init>
OGNL 表达式执行
ognl.OgnlParser.topLevelExpression()
XXE
com.sun.org.apache.xerces.internal.util.XMLResourceIdentifierImpl()
org.apache.xerces.util.XMLResourceIdentifierImpl的setValues()
JSTL import
org.apache.taglibs.standard.tag.common.core.ImportSupport.targetUrl()
DubboRPC
com.alibaba.dubbo.rpc.filter.ContextFilter.invoke()
com.alibaba.dubbo.rpc.filter.GenericFilter.invoke()
SQL 注入
com.mysql.jdbc.StatementImpl
com.mysql.jdbc.PreparedStatement
com.mysql.cj.jdbc.PreparedStatement
org.sqlite.Stmt
org.sqlite.PrepStmt
org.sqlite.jdbc3.JDBC3Statement
org.sqlite.jdbc3.JDBC3PreparedStatement
oracle.jdbc.driver.OracleStatement
oracle.jdbc.driver.OraclePreparedStatement
com.microsoft.sqlserver.jdbc.SQLServerStatement
com.microsoft.sqlserver.jdbc.SQLServerPreparedStatement
org.postgresql.jdbc.PgStatement
org.postgresql.jdbc1.AbstractJdbc1Statement
org.postgresql.jdbc2.AbstractJdbc2Statement
org.postgresql.jdbc3.AbstractJdbc3Statement
org.postgresql.jdbc3g.AbstractJdbc3gStatement
org.postgresql.jdbc4.AbstractJdbc4Statement
com.ibm.db2.jcc.am
com.ibm.db2.jcc.am.Connection
com.ibm.db2.jcc.DB2Driver.connect()
org.eclipse.core.launcher.Main.run()
com.caucho.server.http.ServletInputStreamImpl.read(int)
com.caucho.server.http.ServletInputStreamImpl.read(byte[],int ,int)
HTML注入
com.caucho.server.connection.AbstractHttpResponse.finish()
com.caucho.server.connection.AbstractHttpResponse.finishInvocation()
com.caucho.server.http.AbstractHttpResponse.finish()
com.caucho.server.http.AbstractHttpResponse.finishInvocation()
命令执行(webshell)
目录遍历
XSS(echo)
文件读取
文件写入
文件写入(webshell)
文件拷贝
文件移动
文件上传
文件包含
文件运行(webshell)
SQL注入
SSRF
文件上传
org.apache.commons.fileupload.disk.DiskFileItem.setHeaders()
org.apache.commons.fileupload.FileUploadBase.parseRequest()
文件读取
java.io.FileInputStream(File file)
文件写入
java.io.FileOutputStream()
java.io.FileOutputStream(String name, boolean append)
文件重命名
java.io.File.renameTo()
文件遍历
数据库连接账号
com.mysql.jdbc.NonRegisteringDriver.connect()
com.mysql.cj.jdbc.NonRegisteringDriver.connect()
org.sqlite.JDBC.connect()
com.microsoft.sqlserver.jdbc.SQLServerDriver.connect()
org.postgresql.Driver.connect()
oracle.jdbc.driver.OracleDriver.connect()
Tomcat
org.apache.catalina.startup.Catalina.start()
Jetty
org.eclipse.jetty.server.Server.doStart()
JBoss 4
org.jboss.system.server.ServerImpl.start()
JBoss 5
org.jboss.bootstrap.AbstractServerImpl.start()
JBoss 6
org.jboss.bootstrap.impl.base.server.AbstractServer.start()
Resin
com.caucho.server.resin.Resin.initMain()
preRequest
apache.catalina.connector.CoyoteAdapter.service()
request
apache.catalina.core.ApplicationFilterChain.doFilter()
缓存body
org.apache.catalina.connector.InputBuffer.readByte(int)
org.apache.catalina.connector.InputBuffer.read(byte[],int ,int)
HTML 注入
org.apache.catalina.connector.OutputBuffer.close()
preRequest
com.caucho.server.http.HttpRequest.handleRequest()
com.caucho.server.http.HttpRequest.handleResume()
request
com.caucho.server.dispatch.ServletInvocation.service()
com.caucho.server.dispatch.ServletInvocation.doResume()
缓存body
com.caucho.server.connection.ServletInputStreamImpl.read(int)
com.caucho.server.connection.ServletInputStreamImpl.read(byte[],int ,int)
preRequest
org.eclipse.jetty.server.Server.handle()
request
org.eclipse.jetty.server.handler.HandlerWrapper.handle()
缓存body
org.eclipse.jetty.server.HttpInput.read(int)
org.eclipse.jetty.server.HttpInput.read(byte[],int ,int)
HTML注入
org.eclipse.jetty.server.HttpOutput.close()
preRequest
com.ibm.ws.webcontainer.WebContainer.handleRequest()
request
com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters()
缓存body
com.ibm.ws.webcontainer.srt.http.HttpInputStream.read(int)
com.ibm.ws.webcontainer.srt.http.HttpInputStream.read(byte[],int ,int)
HTML注入
com.ibm.ws.webcontainer.srt.SRTServletResponse.finish()
webshell callable
命令执行
数据库连接账号
java.io.File.list()
WebSphere
修改 Tomcat 启动参数,开启远程调试
配置IDE,连接Tomcat远程调试
可通过设置 JAVA_OPTS 开启远程调试,具体操作如下:
Linux,在 catalina.sh 中 OpenRASP 相关配置相中增加一行,如下,共有两处该配置,都需修改:
Windows,在 catalina.bat 中 OpenRASP 相关配置相中增加一行,如下:
JDWP 配置参数说明
transport=dt_socket 指定通信协议
address=1043 指定调试端口
server=y 指是否支持在server模式的VM中
suspend=y 指是否在调试客户端建立起来后,再执行JVM(调试premain() 需要设置suspend=y)
P.S 在 tomcat 下面直接使用 bin/catalina.sh jpda start 也能达到类似的效果,这样的端口默认是 8000
用Intellij导入OpenRASP源代码;点击 Run -> Edit Configuration
点击左上角加号,选择 Remote
在 Configuration 标签页中,配置 Host,Port以及 源码路径,并点击确认保存。
下好断点后,点击 Run -> Debug 继续执行。如果调试信息窗口出现 Connected to target VM 说明成功连接,如下图:
之后大概等待 3s 左右,如果下了断点,就可以看到堆栈信息了。下面两张图分别为 premain 和 checkXXE 两个断点调试的截图。
在远程调试时,我们发现有些类的断点一直断不上问题,该问题可能出在 IntelliJ 的 Settings -> Debugger -> Stepping 配置上。若勾选了 Do not step into the classes,则会让这些断点失效:
由于是远程调试,OpenRASP 启动日志还是要在 tomcat 日志里看,比如 logs/catalina.out
某支付客户反馈,在 jetty 下面安装 OpenRASP 之后,产生了一些奇怪的问题。经过调试,我们发现是对方使用了非标准SESSION导致的,目前已经解决。如果你也遇到了奇怪的问题,可通过如下方式定位问题:
首先在 openrasp.yml 配置中配置 hooks.ignore: all 来禁用所有 hook 点,然后验证问题是否还存在。如果存在说明问题基本和 OpenRASP 无关。
如果上一步之后问题不存在了,那么就是用上一步中的 hooks.ignore 配置,来一一禁用每个 hook 点,来过滤问题所在的 hook 点。
当找到有问题 hook 点,删除 hooks.ignore 配置,然后使用上文中的 OpenRASP 调试方法,在有问题的 hook 点处设置断点,进行单步调试来进一步锁定问题原因。
方法1: 检查 JavaScript 检测插件是否性能不足
对于单机版,可删除 <app_home>/rasp/plugin/official.js,检查性能是否提升?如果提升很明显,可逐步禁用各个检测算法,找出最消耗性能的算法。
对于开启管理后台的版本,可在管理后台禁用全部检测算法,等一个心跳周期生效后,检查性能是否提升?如果提升很明显,可逐步开启各个检测算法,找出最消耗性能的算法。
方法2: 检查 hook 点是否存在性能瓶颈
修改配置,设置 hooks.ignore: all 并重启服务器。如果性能提升明显,可根据 其他配置选项 里的值,逐步禁用各个 hook 点,找出最消耗性能的 hook 点。
注意: 这个配置不支持远程修改,且修改后需要重启中间件服务器。
方法3: 开启 hook 点调试日志
对于单机版,需要编辑 openrasp.yaml 文件,将 debug_level 设置为 1 并重启服务器。
对于开启管理后台的版本,直接在管理后台修改调试级别即可,设置会在一个心跳周期内生效(默认90s)。
之后每当服务器收到请求,我们就会在 rasp/logs/rasp/rasp.log 里打印这样的日志,
日志里会记录hook点进入的次数、检测逻辑消耗的时间 - 毫秒。若 request_id相同,则表示这些日志是同一个请求产生的。如果你需要调试性能,可以通过这种方式采集日志,并发给我们来分析。
当然,这种日志只需要你访问一次接口即可,不需要压测。
方法4: 开启插件调试日志
下载 999-event-logger.js 并安装到插件目录,然后访问一次你要测试的接口。这个插件会将所有收到的参数打印出来,比如:
这个日志也只需要你访问一次接口,无需压测。
与常规的PHP扩展调试方法一致,使用 gdb 启动 PHP 命令行服务器,下断点调试即可,e.g
其他内容不再赘述
perpage
状态描述
data
具体请求参数
** 响应格式 **:
响应采用 json 格式,示例如下:
** 参数说明**:
page
当前页码
perpage
当前每页数量
total
数据共有多少条
total_page
数据共有多少页
status
响应状态码,0 代表成功,非 0 代表有异常
description
请求结果描述,如果 status 为 0 则为 ok,否则为异常信息
** 接口类型 **:接口分为两类,一类是为前端服务的前端接口,另一类是为 RASP Agent 服务的 Agent 接口,具体接口格式如下文所示。
** 描述 **:用来测试后台联通性的通用接口
** 请求方法 **:GET,POST
** 路径 **:v1/ping
** 请求体 **:空
** 返回结果 **:
** 描述 **:用来获取当前RASP云控后台的版本号
** 请求方法 **:POST
** 路径 **:v1/version
** 请求体 **:空
** 返回结果 **:
认证方式分为两种:
登陆之后获取 cookie 认证,cookie字段为 RASP_AUTH_ID,cookie有效期默认 7 天。
通过在请求头中添加静态 token 进行认证,请求头字段为 X-OpenRASP-Token,具体的 token 管理方式,参照下文 token 管理接口。
** 描述 **:登录接口,初始管理后台用户名:openrasp ,密码:admin@123,登陆成功设置登录 cookie
** 请求方法 **:POST
** 路径 **:v1/user/login
** 请求体 **:
** 参数说明**:
username
String
是
用户名
password
String
是
密码
** 返回结果 **:
** 描述 **: 退出登录状态,清空 cookie
** 请求方法 **:GET
** 路径 **:v1/user/logout
** 请求体 **:无
** 返回结果 **:
** 描述 **: 获取当前是否为登录状态
** 请求方法 **:GET
** 路径 **:v1/user/islogin
** 请求体 **:无
** 返回结果 **:
** 描述 **: 判断当前用户密码是否为默认密码,用于给前端提供是否需要修改密码的提醒
** 请求方法 **:GET,POST
** 路径 **:v1/user/default
** 请求体 **:无
** 返回结果 **:
is_default
是否为默认密码,如果是则为 true,否则为false
** 描述 **:更改管理员密码,密码长度 8~50 个字节,必须同时包含字母和数组
** 请求方法 **:POST
** 路径 **:v1/user/update
** 请求体 **:
** 参数说明**:
old_password
String
是
旧密码
new_password
String
是
新密码
** 返回结果 **:
** 描述** :上传文件为 .js 结尾的插件文件,插件版本在文件第一行,插件名称在插件的第二行
** 请求方法 **:POST
** 路径 **:v1/api/plugin?app_id=c593342c72eb78fc8e7393d0a87b8f3fc54dfbec
** 请求体 **: form data 格式的文件参数,参数名称 plugin
** 参数说明**:
app_id
String
是
APP 唯一标识
plugin
file
是
插件文件,form-data 格式
** 返回结果 **:
id
插件唯一标识
app_id
插件所属的 APP
upload_time
上传时间的时间戳
version
插件版本
name
插件名称
md5
插件内容校验和
** 描述 ** :根据插件 id 下载插件
** 请求方法 **:GET
** 路径 **:v1/api/plugin/download?id=47af9da31ec3f233f35a25776f5e06086ebf239ff60a021ada4750b65640d0d24b9ae382
** 请求体 **: 无
** 参数说明**:
id
String
是
插件唯一标识
** 返回结果 **:插件文件,文件名称为 {NAME}-{VERSION}.js,{VERSION} 为插件版本,{NAME}为插件名称
** 描述 ** :根据插件 id 获取插件
** 请求方法 **:POST
** 路径 **:v1/api/plugin/get
** 请求体 **:
** 参数说明**:
id
String
是
插件唯一标识
** 返回结果 **:
id
插件唯一标识
app_id
插件所属的 APP
upload_time
上传时间的时间戳
version
插件版本
name
插件名称
md5
插件内容校验和
** 描述 ** :给插件下发插件算法开关配置,下发的算法配置会合并到插件中
** 请求方法 **:POST
** 路径 **:v1/api/plugin/algorithm/config
** 请求体 **:
** 参数说明**:
id
String
是
插件唯一标识
config
object
是
算法配置
** 返回结果 **:
** 描述 ** :根据插件 id 恢复插件最开始的默认算法配置
** 请求方法 **:POST
** 路径 **:v1/api/plugin/algorithm/restore
** 请求体 **:
** 参数说明**:
id
String
是
插件唯一标识
** 返回结果 **:
** 描述 ** :根据插件 id 删除插件,无法删除被选中的插件
** 请求方法 **:POST
** 路径 **:v1/api/plugin/delete
** 请求体 **:
** 参数说明**:
id
String
是
插件唯一标识
** 返回结果 **:
** 描述 ** :新增一个 APP
** 请求方法 **:POST
** 路径 **:v1/api/app
** 请求体 **:
** 参数说明**:
name
String
是
APP 名称,名称不能重复
language
String
是
APP 业务语言
description
String
否
** 返回结果 **:
id
APP 唯一标识
name
APP 名称
description
APP 描述信息
language
APP 使用的编程语言
create_time
APP 创建时间
secret
APP 秘钥,用于和 RASP 通信认证
** 描述 ** :删除一个 APP ,同时删除该 APP 下所有的 RASP 和插件,当仅剩一个 APP 无法删除,至少保留一个 APP,无法删除还存在在线 RASP 的 APP
** 请求方法 **:POST
** 路径 **:v1/api/app/delete
** 请求体 **:
** 参数说明**:
id
String
是
APP 唯一标识
** 返回结果 **:
** 描述 ** :获取所有App,或某一个 id 的 app,如果参数中有 id 参数,则返回相应id的 app,如果没有 id 参数,则需要 page 和 perpage 参数来做分页,返回相应数量的 APP 数组
** 请求方法 **:POST
** 路径 **:v1/api/app/get
** 请求体 **:
获取相应 id APP
按照APP名称检索
获取一定数量 APP
** 参数说明**:
app_id
String
否
APP 唯一标识,有该参数则返回相应 id 的 APP
name
String
否
APP 名称,支持模糊查询
page
int
否
** 返回结果 **:
返回相应 id APP
返回一定数量 APP
描述:给 app 下发 rasp 通用配置
请求方法:POST
路径:v1/api/app/general/config
请求体:
** 参数说明 **:
app_id
String
是
APP 唯一标识
config
object
是
通用配置完整内容
** 返回结果 **:返回更新之后的完整 APP 信息
** 描述 **:给 app 下发 rasp 白名单配置
** 请求方法 **:POST
** 路径 **:v1/api/app/whitelist/config
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
config
object
是
白名单配置完整内容
** 返回结果 **:返回更新之后的完整 APP 信息
** 描述 **:给 app 下发报警配置
** 请求方法 **:POST
** 路径 **:v1/api/app/alarm/config
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
attack_type_alarm_conf
Object
否
如果没有该配置,那么将会按照所有攻击类型会触发所有的报警方式,配置中的 key 是攻击类型,value 是该类型会触发的报警方式的列表,目前报警方式包括 ding,http,email
email_alarm_conf
Object
否
** 返回结果 **:返回更新之后的完整 APP 信息
** 描述 **:下发 APP 配置,用于配置 APP 名称,语言和描述信息
** 请求方法 **:POST
** 路径 **:v1/api/app/config
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
name
String
是
APP 名称
language
String
是
** 返回结果 **:返回更新之后的完整 APP 信息
** 描述 **:根据 APP ID 获取所有的插件内容
** 请求方法 **:POST
** 路径 **:v1/api/app/plugin/get
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
page
int
是
页码
perpage
int
是
** 返回结果 **:
** 描述 **:获取 APP 当前选中的插件,该插件会下发给 APP 下的 RASP
** 请求方法 **:POST
** 路径 **:v1/api/app/plugin/select/get
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
** 返回结果 **:
** 描述 **:设置 APP 下发给 RASP 的插件
** 请求方法 **:POST
** 路径 **:v1/api/app/plugin/select
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
plugin_id
String
是
插件唯一标识
** 返回结果 **:
** 描述 **:导出所有 APP 的ID、Secret等信息
** 请求方法 **:GET
** 路径 **:v1/api/app/export
** 返回结果 **:包含app信息的 json 文件
** 描述 **:测试邮件报警
** 请求方法 **:POST
** 路径 **:v1/api/app/email/test
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
** 返回结果 **:
** 描述 **:测试钉钉报警
** 请求方法 **:POST
** 路径 **:v1/api/app/ding/test
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
** 返回结果 **:
** 描述 **:测试 HTTP 报警
** 请求方法 **:POST
** 路径 **:v1/api/app/http/test
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
** 返回结果 **:
** 描述 **:测试 Kafka 报警
** 请求方法 **:POST
** 路径 **:v1/api/app/kafka/test
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
** 返回结果 **:
** 描述 **:如果当前插件是 official.js 的话,判断当前下发插件是否为最新官方插件。如果不是(如 iast.js),返回当前下发插件和最新插件的版本信息
** 请求方法 **:POST
** 路径 **:v1/api/app/plugin/latest
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
** 返回结果 **:
is_latest
当前下发插件是否为最新版本
selected_version
当前下发的插件版本
latest_version
最新插件版本
** 描述 **:按照条件搜索 RASP
** 请求方法 **:POST
** 路径 **:v1/api/rasp/search
** 请求体 **:
** 参数说明 **:
id
String
否
RASP 唯一标识
app_id
String
否
所属的 APP 的 ID
version
String
否
** 返回结果 **:
id
RASP 唯一标识
app_id
所属的 APP 的 ID
version
RASP 版本
hostname
RASP 所在的主机名,该字段支持模糊搜索,并同时搜索 hostname 和 register_ip 字段
register_ip
RASP 访问云控后台所使用的 IP 地址
language
编程语言
** 描述 **:统计RASP每个版本号下主机个数
** 请求方法 **:POST
** 路径 **:v1/api/rasp/search/version
** 请求体 **:
** 参数说明 **:
app_id
String
是
所属的 APP 的 ID
version
String
否
指定搜索的版本号
** 返回结果 **:
version
主机版本号
count
主机版本号对应的主机个数
** 描述 **:按条件搜索 rasp,并把搜索结果导出到 csv 文件,app_id 字段为必选,剩余搜索条件为可选
** 请求方法 **:GET
** 路径 **:v1/api/rasp/csv?app_id=eaGdr22DfthDz51JHF65sd
** 参数说明 **:
app_id
String
是
所属的 APP 的 ID
** 返回结果 **: csv 文件
** 描述 **:删除指定条件的 RASP,在线的 rasp 不允许删除,当参数中存在 id,删除指定 id 的 rasp 并忽略其他参数
** 请求方法 **:POST
** 路径 **:v1/api/rasp/delete
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
id
String
否
RASP 唯一标识
register_ip
String
否
** 返回结果 **:
count
删除 RASP agent 数量
** 描述 **:根据 rasp id 批量删除rasp
** 请求方法 **:POST
** 路径 **:v1/api/rasp/batch_delete
** 请求体 **:
** 参数说明 **:
app_id
String
是
APP 唯一标识
ids
String Array
是
RASP 唯一标识列表
** 返回结果 **:
count
删除 RASP agent 数量
** 描述 **:给指定 id 的 rasp 添加或者修改备注信息
** 请求方法 **:POST
** 路径 **:v1/api/rasp/describe
** 请求体 **:
** 参数说明 **:
id
String
是
RASP 唯一标识
description
String
是
描述信息
** 返回结果 **:
** 描述 **:按照应用下主机聚合主机的类库信息
** 请求方法 **:POST
** 路径 **:v1/api/dependency/aggr
** 请求体 **:
** 参数说明 **:
app_id
String
是
所属的 APP 的 ID
** 返回结果 **:
timestamp
类库信息上传时间
app_id
所属的APP的ID
hostname
主机名称
id
类库信息唯一标识
path
类库依赖路径
product
产品名称
** 描述 **:查看类库信息的详情
** 请求方法 **:POST
** 路径 **:v1/api/dependency/search
** 请求体 **:
app_id
String
是
APP 唯一标识
tag
String
key_word
String
否
** 返回结果 **:
app_id
所属的APP的ID
timestamp
类库信息上传时间
hostname
主机名称
id
类库信息唯一标识
path
类库依赖路径
product
产品名称
** 描述 **:当有 token 参数为更新,否则为新增 token
** 请求方法 **:POST
** 路径 **:v1/api/token
** 请求体 **:
新增token:
更新token:
** 参数说明 **:
token
String
是
token 内容
description
String
否
token 描述
** 返回结果 **:
** 描述 **:获取一定数量的 token 信息
** 请求方法 **:POST
** 路径 **:v1/api/token/get
** 请求体 **:
** 返回结果 **:
** 描述 **:删除 token
** 请求方法 **:POST
** 路径 **:v1/api/token/delete
** 请求体 **:
** 返回结果 **:
** 描述 **:搜索操作日志
** 请求方法 **:POST
** 路径 **:v1/api/operation/search
** 请求体 **:
** 参数说明 **:
data
String
是
所有支持搜索的字段,data 中所有字段皆为可选
start_time
int
是
操作日志的开始时间,毫秒时间戳
end_time
int
是
** 返回结果 **:
id
操作日志唯一标识
app_id
所属的 APP 的 ID
type_id
日志类型
time
操作时间
user
操作人
content
操作内容
** 描述 **:获取 panel 和 agent 服务器的 url 地址
** 请求方法 **:POST
** 路径 **:v1/api/server/url/get
** 参数 **:无
** 返回结果 **:
panel_url
前端 server url 访问地址
agent_url
agent server 访问地址列表
** 描述 **:更改 panel 和 agent 服务器的访问地址
** 请求方法 **:POST
** 路径 **:v1/api/server/url
** 请求体 **:
** 参数说明 **:
panel_url
String
是
前端 server url 访问地址
agent_url
String Array
否
agent server 访问地址列表
** 返回结果 **:
** 描述 **:清空数据库中的攻击事件、基线报警、异常日志、请求数量、崩溃信息
** 请求方法 **:POST
** 路径 **:v1/api/server/clear_logs
** 请求体 **:
** 参数说明 **:
app_id
前端 server url 访问地址
** 返回结果 **:
** 描述 **:按照时间聚合 RASP 上传的请求统计数据
** 请求方法 **:POST
** 路径 **:v1/api/report/dashboard
** 请求体 **:
** 参数说明 **:
app_id
String
是
需要聚合的 APP
start_time
int
是
开始时间
end_time
int
是
** 返回结果 **:
start_time
开始时间
request_sum
RASP 处理的请求数量
为了降低 es 压力,所有报警接口起止时间不能超过 366 天,聚合接口 size 不能超过1024
** 描述 **:按照时间聚合攻击数据
** 请求方法 **:POST
** 路径 **:v1/api/log/attack/aggr/time
** 请求体 **:
** 参数说明 **:
app_id
String
是
需要聚合的 APP
start_time
int
是
开始时间
end_time
int
是
** 返回结果 **:
data
聚合数据,第一个元素是 info 数据,第二个是 block 数据
labels
聚合的横轴时间标签数组,每个元素都是一个毫秒时间戳
** 描述 **:按照攻击类型聚合攻击数据
** 请求方法 **:POST
** 路径 **:v1/api/log/attack/aggr/type
** 请求体 **:
** 参数说明 **:
app_id
String
是
需要聚合的 APP
start_time
int
是
开始时间
end_time
int
是
** 返回结果 **:
data
聚合数据,每个数组代表一种类型,每个数组的第一个元素代表类型名称,第二个元素代表该类型的攻击数量
** 描述 **:按照请求 User-Agent 头聚合攻击数据
** 请求方法 **:POST
** 路径 **:v1/api/log/attack/aggr/ua
** 请求体 **:
** 参数说明 **:
app_id
String
是
需要聚合的 APP
start_time
int
是
开始时间
end_time
int
是
** 返回结果 **:
data
聚合数据,每个数组代表一种类型,每个数组的第一个元素代表 UA 名称,第二个元素代表该 UA 的攻击数量
** 描述 **:按照漏洞聚合攻击数据(不同的栈为不同的漏洞)
** 请求方法 **:POST
** 路径 **:v1/api/log/attack/aggr/vuln
** 请求体 **:
** 参数说明 **:
app_id
String
否
漏洞所属的 APP,如果有该参数,那么统计相应的 app 数据,如果没有,则统计所有的数据
attack_type
String Array
否
攻击类型可以多选,数组为空则什么都不返回,没有该参数,或者参数为null,则不过滤此参数
rasp_id
String
否
** 返回结果 **:
data
漏洞聚合结果,结果按照每个漏洞的最新的攻击时间排序,每个漏洞展示的内容都是该漏洞最新的一个攻击的内容
** 描述 **:搜索攻击日志,结果结果按照时间降序排序
** 请求方法 **:POST
** 路径 **:v1/api/log/attack/search
** 请求体 **:
** 参数说明 **:
app_id
String
否
所属的 APP,如果有该参数,那么统计相应的 app 数据,如果没有,则统计所有的数据
attack_type
String Array
否
攻击类型可以多选,数组为空则什么都不返回,没有该参数,或者参数为null,则不过滤此参数
rasp_id
String
否
** 返回结果 **:
data
搜索攻击结果
** 描述 **:搜索崩溃日志,结果结果按照时间降序排序。支持按照主机名称、报警信息和报警时间进行检索
** 请求方法 **:POST
** 路径 **:v1/api/log/crash/search
** 请求体 **:
** 参数说明 **:
_id
String
否
崩溃信息ID,用于区分不同的崩溃信息
app_id
String
否
所属的 APP,如果有该参数,那么统计相应的 app 数据,如果没有,则统计所有的数据
hostname
String
否
** 返回结果 **:
data
搜索基线结果
** 描述 **:搜索基线日志,结果结果按照时间降序排序
** 请求方法 **:POST
** 路径 **:v1/api/log/policy/search
** 请求体 **:
** 参数说明 **:
app_id
String
否
所属的 APP,如果有该参数,那么统计相应的 app 数据,如果没有,则统计所有的数据
policy_id
int Array
否
该字段可以多选,数组为空则什么都不返回,没有该参数,或者参数为null,则不过滤此参数
rasp_id
String
否
** 返回结果 **:
data
搜索基线结果
** 描述 **:根据条件搜索异常信息
** 请求方法 **:POST
** 路径 **:v1/api/log/error/search
** 请求体 **:
** 参数说明 **:
app_id
String
否
所属的 APP,如果有该参数,那么统计相应的 app 数据,如果没有,则统计所有的数据
rasp_id
String
否
攻击所属的 RASP 的 ID
server_hostname
String
否
** 返回结果 **:
data
搜索错误日志结果
增加 APP ID 请求头: X-OpenRASP-AppID: 9b3554a97673f1f8f5c929310298037a660d3b7a
增加 APP Secret 请求头: X-OpenRASP-AppSecret: 2wMG8K9F71CZyvlWu1CRwf7tVDVW7Ud4gxCY5X4aMzO
** 描述 **:注册 RASP 基本信息,如果有 id 参数,那么为更新相应的 RASP 信息,否则为新增 RASP
** 请求方法 **:POST
** 路径 **:v1/agent/rasp
** 请求体 **:
** 参数说明 **:
id
String
是
RASP 唯一标识
version
String
是
RASP 版本
hostname
String
是
** 返回结果 **:
** 参数说明 **:
id
RASP 唯一标识
app_id
所属 APP 标识
version
RASP 版本
hostname
RASP 所在机器的主机名
register_ip
RASP 所在机器 IP 地址
language
RASP 使用的开发语言
** 描述 **:接受 RASP 向云控后台的定时心跳,如果请求参数中的 md5 和后台指定的插件 md5 不同则判定有新插件,如果配置时间小于云控后台的最后配置时间,判定有新配置,每次更新都是插件和配置的全量更新。
** 请求方法 **:POST
** 路径 **:v1/agent/heartbeat
** 请求体 **:
** 参数说明 **:
rasp_id
String
是
RASP 唯一标识
plugin_md5
String
是
当前 RASP 的插件 MD5
plugin_version
String
是
** 返回结果 **:
** 参数说明 **:
plugin
插件内容
config_time
本次下发配置的时间
config
下发的配置,配置项的详细说明:
** 描述 **:上传 rasp 统计信息
** 请求方法 **:POST
** 路径 **:v1/agent/report
** 请求体 **:
** 参数说明 **:
rasp_id
String
是
RASP 唯一标识
time
int
是
统计时间,毫秒时间戳
request_sum
int
否
** 返回结果 **:
** 描述 **:上传 rasp 奔溃信息
** 请求方法 **:POST
** 路径 **:v1/agent/crash/report
** 请求体 **:
格式: multipart/form-data
内容:
crash_log: hs_err_pid25945.log
hostname: Mac-xxxx-host
language: java
rasp_id: d5ged5g54dr1gdr5d5erg5rdg
** 参数说明 **:
crash_log
文件
是
崩溃日志
rasp_id
String
是
RASP 唯一标识,RASP 可以不存在
language
String
否
** 返回结果 **:
** 描述 **:上传 RASP 攻击日志
** 请求方法 **:POST
** 路径 **:v1/agent/log/attack
** 请求体 **:
** 参数说明 **:攻击日志数组,包含多条攻击日志,日志字段说明:https://rasp.baidu.com/doc/setup/log/main.html
** 返回结果 **:
count
成功处理的日志数量
** 描述 **:根据主机上传类库信息
** 请求方法 **:POST
** 路径 **:v1/agent/dependency
** 请求体 **:
** 参数说明 **:
rasp_id
String
是
所属的 RASP
product
String
是
产品名称
version
String
是
** 返回结果 **:
** 描述 **:基线报警内容,基线报警会根据 "stack_trace,rasp_id, policy_id, policy_param “ 几个字段进行去重操作,这几个字段相同的报警只会出现一次。
** 请求方法 **:POST
** 路径 **:v1/agent/log/policy
** 请求体 **:
** 参数说明 **:基线日志数组,包含多条基线日志,极限报警字段说明:https://rasp.baidu.com/doc/setup/log/main.html
** 返回结果 **:
count
成功处理的日志数量
** 描述 **:上传异常日志
** 请求方法 **:POST
** 路径 **:v1/agent/log/error
** 请求体 **:
** 参数说明 **:错误日志数组,包含多条错误日志,字段说明同上文基线报警字段说明。
** 返回结果 **:
count
成功处理的日志数量
** 描述 **:用于认证 app id 和 app secrete
** 请求方法 **:POST
** 路径 **:v1/agent/auth
** 请求体 **:空
** 返回结果 **:
** 请求格式 **:
请求体采用 json 格式,分页页码从 1 开始计数,分页请求格式如下所示:
** 参数说明 **:
order
任务类型。
host
扫描目标主机
** 响应格式 **:
响应采用 json 格式,示例如下:
** 参数说明 **:
data
扫描器返回给云控后台的内容
app_id
APP 唯一标识
register
扫描器状态:0表示扫描器未连接,1表示正在连接中,2表示扫描器连接成功,3表示接收响应异常,4表示扫描器连接超时
data.status
错误码
增加请求头: Content-Type: application/json
** 描述 **:获取当前云控后台版本号
** 请求方法 **:POST
** 路径 **:v1/iast/version
** 请求体 **:空
** 返回结果 **:
** 描述 **:为扫描器新建扫描任务
** 请求方法 **:POST
** 路径 **:v1/iast
** 请求体 **:
order
String
是
任务类型。startTask表示新建扫描
host
String
是
扫描目标主机
port
String
是
** 返回结果 **:
data
扫描器返回给云控后台的内容
app_id
APP 唯一标识
register
扫描器状态。2表示扫描器连接成功
data.status
错误码:2 并发扫描任务达到限制 , 3 目标正在被其他任务扫描
** 描述 **:修改目标主机的扫描配置
** 请求方法 **:POST
** 路径 **:v1/iast
** 请求体 **:
order
String
是
任务类型。setConfig表示修改配置
host
String
是
扫描目标主机
port
String
是
** 返回结果 **:
data.status
错误码:2 白名单正则不合法, 3 代理协议不为http或https
** 描述 **:获取目标主机的扫描配置
** 请求方法 **:POST
** 路径 **:v1/iast
** 请求体 **:
order
String
是
任务类型。getConfig表示获取配置
host
String
是
扫描目标主机
port
String
是
** 返回结果 **:
scan_plugin_status
插件开关
max_concurrent_request
最大并发请求数
max_request_interval
最大请求间隔
min_request_interval
最小请求间隔
app_id
APP 唯一标识
** 描述 **:立即终止指定的扫描任务
** 请求方法 **:POST
** 路径 **:v1/iast
** 请求体 **:
order
String
是
任务类型。getConfig表示获取配置
scanner_id
Int
是
扫描任务id
app_id
String
是
** 返回结果 **:
data.status
错误码:2 指定的扫描任务不存在,3 终止失败
** 描述 **:获取所有安装rasp agent的主机(agent至少发送过一次http请求结果)
** 请求方法 **:POST
** 路径 **:v1/iast
** 请求体 **:
app_id
String
是
APP 唯一标识
order
String
是
指令参数。"getAllTasks"表示获取所有目标
** 返回结果 **:
** 参数说明 **:
app_id
APP 唯一标识
host
扫描器返回的数据,接口说明详见
port
端口号
total
该目标下的总url数
scanned
该目标下的扫描的url数
failed
该目标下扫描失败的url数
** 描述 **:清空目标主机的信息(重置为一个未配置的agent状态),或清空url列表
** 请求方法 **:POST
** 路径 **:v1/iast
** 请求体 **:
order
String
是
任务类型。cleanTask表示清除任务
host
String
是
扫描目标主机
port
String
是
** 返回结果 **:
data.status
错误码:2 目标正在被扫描
page
页码
线下安全测试使用
无论是哪种情况,请说明以下几点:
当前算法存在哪些问题,你需要解决什么问题?
可以同时提供漏洞测试用例
新算法误报情况如何,是否会影响服务器性能?
如果性能不符合要求,但是算法被接受,我们会合并代码,但默认在配置里禁用这个功能
对于有特殊应用场景,但不通用的算法,处理方法同上
对于检测点的改进,请注意:
如果是SQL相关的改进
请尽量支持全部数据库 - MSSQL、PGSQL、MySQL、SQLite、DB2
如果不能,我们可以先合并代码,但默认在配置里禁用这个新功能
除特殊情况,只有在全部数据库支持后,我们才能正式说明支持了这个功能
如果你没有系统环境,比如 DB2,我们可以排期开发
可以使用 docker 进行自动化测试,这是我们目前使用的镜像列表
microsoft/mssql-server-linux:2017-GA
alexeiled/docker-oracle-xe-11g
mysql:5
请提供测试用例,包括漏洞利用方法、正常的请求如何发起
通常,我们在 contributer 名单里加上你的名字。当然,如果你想匿名提交代码,我们也可以不修改这个名单
在线上部署之前,请先联系QA在测试环境进⾏压⼒测试,并关注下⾯这些问题:
平均请求响应时间下降多少?
如果CPU打满,QPS会下降多少?
我们测试了大量的业务系统,也测试了多个开源应⽤;很多金融客户帮助我们进行了全链路的压测。性能影响通常
在 2%~4% 之间,接口响应延迟在 2~8ms 之间,完全可以接受。
如果你发现实际的性能损耗超过了 5%,请参考性能调试 文档,采集调试数据,然后加⼊QQ群联系群主。我们会在第⼀时间进⾏分析,并尽快解决问题。
本报告只是抛砖引玉,如果你有任何疑问,欢迎加入QQ技术讨论群一起探讨。
JeeCMS 本身存在性能瓶颈,在不安装OpenRASP的情况下,当并发达到15,2个CPU已经打满,所以我们无法模拟更多用户
php-fpm 配置为,
pm=static
max_children=100
max_requests=1000
测试结果
php-fpm 配置为,
pm=static
max_children=100
max_requests=1000
测试结果
管理后台
支持按照主机名、RASP ID或者主机IP搜索报警
增加心跳时间索引,解决大规模主机搜索卡顿问题
为了提高查询效率,主机离线判定方式改为固定的360s,不再根据心跳配置动态计算
支持在后台导出单条报警
支持删除过期依赖库数据,感谢@国产大熊猫反馈
升级beego到v1.12.3,感谢@大剑士反馈后台编译问题
Kafka推送时,将@timestamp从数字改为字符串,
增加漏洞级别字段,aka event_level
推送测试报警时,不再使用写死的假报警,而是从ES里搜索最新的报警作为测试数据
合入@strawberrybiscuits的补丁,解决IAST死锁问题
Java 版本
修复当Java不在$PATH时,resin安装会抛出异常的问题,感谢 @叶 反馈
修复WebLogic Windows下面自动安装失败的问题
修复Weblogic下面无法加载的问题(v1.3.3 引入)
修复log.path配置不生效的问题
PHP 版本
增加PHP 7.4支持
修复PHP 5.5下面,include检测点可能会崩溃的问题
检测插件
修复 @月射寒江 发现的Oracle SQL异常无法报警的问题
修复 @mattF123 报告的多个XXE绕过问题
按照 @Holy 的建议,增加反射写jspx文件的检测
管理后台
支持按照RASP目录搜索主机
修复部分报警展示问题
依赖库详情页面,改为按照上报时间排序
修复后台审计日志IP伪造问题,感谢 @k4n5ha0 反馈
Java 版本
支持 MySQL 8.X 驱动
支持开启jnotify、关闭jnotify,或者定期扫描插件目录三种方式;默认改为定期扫描
支持关闭依赖库采集(安装阶段通过 -nodep 参数关闭)
PHP 版本
扩展 webshell_ld_preload 检测点,支持配置环境变量,新版插件默认支持3个
后端请求错误时,同时打印 cURL 错误描述(之前版本仅有错误码)
依赖库数据增加缺失的来源字段,内容固定为 composer
检测插件
修复腾讯报告的SQL注入绕过问题
优化身份证合法性校验逻辑
反序列化、OGNL两个检测算法,黑名单支持配置(需要同时升级后台和插件)
管理后台
由于早期 ElasticSearch mapping 的问题,当 URL 长度超过一定值,将无法搜索到
后台升级完成后,用户需要手动执行 ./rasp-cloud -upgrade 134to135 来更新 mapping
程序会先修改 alias,将索引指向新的 alias,完成数据复制后才删除以前的索引
复制过程中可以有新的报警数据写入,不会丢失
Java 版本
修复自定义 header 失效问题
修复XSS检测,会打印空指针日志问题
修复内置检测插件异常时,不会打印URL的问题
修复 java.io.RandomAccessFile 读操作误报问题
PHP 版本
修复某些 PHP 5.3 的环境,获取到的 header 可能为空的问题
修复插件里正则写错时,会抛出异常的问题
修复在云控连接成功前,就启动web目录敏感文件检测,导致匹配错误的问题
加强 array_map 兼容性,避免第一个参数为空时打印多余日志
Java 版本
增加宝兰德BES支持,感谢 @枫舞蝶殇 提交的补丁
修复某些情况下,Tomcat 9 启动时候可能会卡顿的问题
修复某些 yum 安装的 tomcat 服务器,RaspInstall 会失败的问题
增加 yaml 反序列化白名单,感谢 @kkskk 提交的补丁
检测插件
SQL注入: 内部有误报场景,默认关闭十六进制字符串检查
任意文件写入: 拦截基于反序列化写webshell的操作,如fastjson漏洞
管理后台
应用快速切换,改为动态搜索,并展示前100个匹配结果
攻击事件详情增加RASP版本展示
支持自定义日志路径,配置名称为 LogPath
如不配置,默认为 /home/openrasp/logs
通用改进
增加 Alpine docker 环境支持
Java 版本
捕获 UTF16 转换异常
PHP 版本
修复 PHP 5.3.18 之前版本,某些情况下RASP进程会意外退出的问题
管理后台
修复平安报告的 request.param_encoding 默认值错误问题,应该设置为空
Java 版本
修复 @素十八 报告的攻击无法拦截的问题
PHP 版本
修复SSRF重定向检测时,若URL不带协议头,cURL会增加 http://,导致误报的问题
管理后台
修复Web根目录敏感文件正则默认配置,删除多余的双引号
添加主机界面,优化手动安装提示
Java 版本
修复 SpringBoot 在开启白名单后,可能会导致所有 Hook 点失效的问题
PHP 版本
增加 fastcgi SAPI 支持(之前的版本只支持 php-fpm/apache)
检测插件
敏感信息泄漏检测算法,修正某些情况下手机号识别会误报的问题
当请求JSON解析出错时,对异常日志进行截断,避免硬盘打满
拦截基于 CVE-2020-9547、CVE-2020-8840 的命令执行
IAST 扫描工具
IAST 控制台合入现有管理后台,降低运维成本(iast 不再监听 18664 端口)
IAST 扫描器改为连接 panel 服务器(以前是连接 agent 服务器)
IAST 扫描器使用 websocket 连接管理后台,不兼容 v1.3.0 之前的后台
老版本后台用户可使用 pip3 命令安装老版本
PHP 版本
对于文件相关检测点,若读取文件以流协议开头,将会触发SSRF检测,不会触发文件读写检测
受影响协议为: https/http/ftp
受影响函数为: file/readfile/file_get_content/fopen/copy/include
当 plugin.filter 关闭,文件相关检测点将忽略 open_basedir 配置,继续进入插件检测
通用改进
增加文件删除测点
增加 SSRF 跳转后检测点,可检测重绑定攻击
增加 HTML 响应检测点,默认每分钟采样5次
增加依赖库信息采集,默认6小时采集一次
Java 版本
增加 Hibernate SQL 检测点
增加 nio 检测点
增加 SpringBoot 部分注解参数支持
PHP 版本
SSRF 支持 IPv6 地址解析
基线检查: 检测web根目录下是否有压缩包、SQL等敏感文件
增加 mysql_db_query、mysql_unbuffered_db_query 检测点
增加 print 检测点
管理后台
新增 -s restart / -s stop / -s status 指令,可以重启后台、关闭后台以及获取状态
支持主机设置备注,以及按照备注搜索
白名单支持备注
支持日志写 kafka
检测插件
增加任意文件删除漏洞检测
增加 header 注入检测(如SQL注入、命令注入)
增加命令执行语法错误监控,以及可疑的注入检测
增加 DNS Rebind 方式的 SSRF 攻击
Java 版本
RaspInstall 安装 rasp.jar 时,先重命名再写入新文件
避免修改已经加载的 jar,可能会出现 mmap 问题
老文件以 uuid 随机命名,支持多次安装,会在启动时统一删除
PHP 版本
当后台下发配置不符合预期,主动上报异常日志
修复 Kali 下面日志只会上传一条的问题,感谢 @亿相逢 反馈
修复某些情况下,会出现多个 rasp-log 进程的问题
管理后台
客户端版本聚合接口,没有过滤主机在线状态
增加重复白名单校验
通用改进
Java、PHP 增加崩溃监控(仅支持 Linux/Mac 系统)
监控信号如 segfault/abort 等等
监控范围是 Java主进程、PHP worker/心跳/日志进程/守护进程
崩溃后自动向管理后台发出报警,并上传堆栈日志;后台会同步发出邮件报警
管理后台
支持客户端版本枚举
支持一键关闭所有报警
当agent无法获取dubbo等应用版本号时,允许agent注册
Java 版本
修复 syslog 地址修改后,依然会向老地址发送日志的问题(感谢 @й阿桂 反馈)
管理后台
后台升级完成后,还需要再手动执行 ./rasp-cloud -upgrade 121to122 来更新 MongoDB
增加 X-Protected-By: OpenRASP 相关配置
请求 body 大小限制改为 12KB
通用改进
彻底解决 v8::Abort() 崩溃问题
升级 v8 到最新版本: 7.8.279.19
支持隐藏 X-Protected-By: OpenRASP 响应头
自动安装程序
支持通过 -heartbeat/--heartbeat 参数自定义心跳间隔
Java 版本
增加 WebSphere 7.X 支持。由于IBM JDK限制,文件相关检测点无法生效
当插件没有注册 request/requestEnd 检测点,不再构造相关参数以提高性能
检测插件
拦截基于 bsh.servlet.BshServlet 的命令执行操作,e.g CNVD-2019-32204
拦截基于 jdk.scripting.nashorn 的命令执行操作
Java 版本
修复部分情况下,Java 无法获取字符流请求 body 的问题
PHP 版本
修复当关闭 plugin.filter 时,包含 .php/.inc 文件不会进入插件的问题
对于 multipart 请求,单独提取参数,解决产生报警时没有请求 body 的问题
检测插件
修复用户报告的 replaceAll 函数内存占用过高问题
修复 @Looke 报告的 xss_userinput 绕过问题
管理后台
由于早期 ElasticSearch mapping 的问题,对于已经存在的应用,报警消息、基线消息、异常消息均不支持大小写搜索
后台升级完成后,用户需要手动执行 ./rasp-cloud -upgrade 120to121 来更新 mapping
程序会先修改 alias,将索引指向新的 alias,完成数据复制后才删除以前的索引
复制过程中可以有新的报警数据写入,不会丢失
通用改进
支持自定义 RASP ID
安装时使用 --rasp-id (PHP) 或者 -raspid (Java) 来设置
若没有指定,则按照先前的逻辑,根据网卡、RASP路径等信息计算一个
管理后台
增加报警日志去重,目前按照 request_id + stack_md5 进行去重
在 系统设置 -> 后台设置 界面,增加一键清理报警数据支持
主机管理界面,自动记住 主机状态 勾选情况
报警查看界面,支持按照报警消息、堆栈MD5搜索;Referer、URL 支持点击
Java 版本
增加 TongWeb 6.X 服务器部分支持,
简化 JBoss 7 以及更高版本的安装流程,
增加 HSQL 数据库 hook 点,可以检测 WebGoat SQL 注入漏洞
插件系统
命令执行检测点,增加环境变量信息
SQL异常检测改为插件检测,且可在管理后台自定义要监控的错误代码
修复 command_reflect 算法,在某些情况下可能误报的问题
通用修复
增加重新注册支持,当主机离线后被误删除,可自动恢复
Java 版本
修复当中间件支持 multipart 协议,但是用户没有使用文件时,会产生误报的问题
修复当服务器在启动一段时间后才与管理后台连通,Java Agent 不会再次获取注册IP的问题
修复某些情况下,由于 context.language 为空,不会拦截 WebSphere 反序列化命令执行的问题
修复心跳失败时,sleep 失效,会无限打印日志的问题
PHP 版本
修复PDO异常监控没有过滤 error code,记录了多余的异常日志的问题
通用变更
删除 enforce_policy 配置,基线检测不再支持拦截
去除 MySQL duplicated key 错误监控
删除报警日志里的 stack_trace 字符串字段,统一使用 attack_params.stack 获取堆栈
若 Java/PHP agent 升级到 v1.2.0,那管理后台也必须升级,否则前端堆栈将展示为空值,且漏洞聚合列表将为空
通用改进
主机名发生变化时,同步到管理后台
增加 host_type 字段,以标识是否为docker容器
管理后台
修复登录后无法跳回原URL的问题
插件系统
增加 requestEnd hook 点,请求结束时调用一次
增加 RASP.request() 接口,可在插件里发送 HTTP 请求
增加 RASP.get_version() 接口,可获取 agent 版本信息
增加 context.requestId 等多个字段
PHP 版本
增加 eval/assert hook 点
增加 debuglevel 配置,避免打印多余日志
Java 版本
对 JBoss、WebLogic 增加集群支持
修复 v8 在多线程环境运行时,获取 Thread Local 数据会崩溃的问题
增加关键hook点检查: requestEnd, request.parameterMap 不存在时拒绝启动
心跳间隔下限改为 10s
自动安装程序
增加 SpringBoot 半自动安装,即只释放文件并修改配置,参数名为 -nodetect
增加对 yum 安装的 tomcat 的支持,即 bin 目录与 tomcat_home 分离的情况
增加 -prepend 参数,若开启则将 -javaagent 参数放在最前面
灰盒扫描工具
发布第一版,结合RASP挖掘漏洞的扫描器
Java 版本
解决 JRockit 兼容性问题,改为 jni 获取网卡信息
解决 org.elasticsearch.client.RestClient 兼容性问题
解决 XXE 代码安全开关和 taglib 不兼容的问题
屏蔽 V8 execstack warning
PHP 版本
修复报警日志里PHP版本号不对的问题
插件系统
修复 001-dir-1.jsp 即使在插件里关闭 all_log 也不会拦截的问题
管理后台
支持按照攻击类型决定是否报警
主机管理页面,支持导出agent列表
添加主机页面,修正 SpringBoot + Docker 安装命令
优化多处表格体验
Java 版本
syslog tcp 增加连接、发送超时
支持通过 rasp.jar 获取agent版本信息
检测插件
readFile hook 点忽略 war 包相关操作
Java 版本
当主机名没有在 /etc/hosts 里绑定,会触发大量 hostname 命令执行调用的 BUG
传给插件的堆栈,修复过滤不正确的问题
修复 Undertow 解析参数时的空指针异常问题
修复一处 XSS hook 点空指针异常
管理后台
开启 gzip 压缩支持,减少网络流量
报警、基线日志保留时间支持自定义,默认 365 天
优化多处前端体验
agent 异常日志增加堆栈详情展示
Java 版本
修复堆栈过滤不全的问题
解决 emoji 表情包可能造成的编码问题
openrasp-v8 所有异常同步到 rasp.log
检测算法
修复 command_reflect 误报问题
删除 xss tag 超过10个就报警的算法
通用变更
升级 Google v8 到 7.2 版本
语法解释器由antlr4替换为flex,降低内存占用
PHP 版本
替换 libstdc++ 为 libc++
去除 pcre 依赖
二进制包增加 Thread Safety 版本
Java 版本
替换 rhino 为 openrasp-v8
SQL、SSRF 检测逻辑改为JS实现
暂时去除 JRockit JDK 支持,WebLogic 10.3.6 需要设置 JAVA_VENDOR=Sun 来改用 Oracle JDK
插件系统
精简 console.log 函数,删除颜色相关代码
传给检测插件的堆栈,过滤掉 com.baidu.openrasp 相关内容
通用变更
SQL异常增加密码错误监控
实现数据库连接弱口令检测
Java 版本
增加XXE代码安全开关,可以直接禁止外部实体加载
通用修复
插件更新成功后,立即发出心跳,解决管理后台版本信息滞后问题
报警堆栈过滤掉 openrasp 相关内容
Java 版本
修复文件上传检测点误报问题,改为在用户使用了文件之后再检测
修复 Windows下,openrasp.yml 文件编码不正确的问题
修复 JBoss 12 以上无法自动安装的问题
解决 JSP 无法获取堆栈的问题
管理后台
修复检测插件重复上传问题
前端首页增加缓存失效设置
修复 debug_level 字段不是数字的问题
当应用下面有在线主机,禁止删除应用
通用变更
报警日志增加 header 字段,并去除最外面的 user_agent、referer 重复字段
单机版配置文件改为 yaml
仅当拦截响应码设置为 302 时才输出 Location 头跳转,使用户可以打印自定义拦截内容
管理后台
在配置文件里删除 AgentServerURL、PanelServerURL 两个项目,改为在管理后台界面上修改
首次访问后台会自动设置上述两个选项,若要开启负载均衡模式,请手动修正 Agent 服务器列表
PHP 版本
单机版默认禁用 fswatch。若有需求请使用 --enable-fswatch 编译参数开启
替换 rapidjson 为接口更加灵活的 nlohmann/json
cli 模式关闭基线检查,避免多余的日志。若有需求请使用 --enable-cli-support 编译参数开启
Java 版本
去除 rasp-log4j.xml 相关启动参数。改为动态生成 log4j 配置的方式,用户不再需要配置
通用功能
新增 JSON 参数解析,即 context.json
新增应用加固功能,可防护点击劫持、MIME嗅探、下载文件自动运行、反射XSS
支持反编译功能,产生报警时可同时获取用户代码(仅 JDK 6-8、PHP 支持)
PHP 版本
新增 PHP 7.3 支持
Java 版本
新增 SpringBoot + Undertow 支持
新增 WebLogic 支持
新增 JBoss 6-8 支持(暂不支持自动安装)
管理后台
改进多处用户体验,提供更加完善的报警搜索体验
新增漏洞聚合展示,避免在漏洞利用阶段攻击刷屏的问题
改进审计日志展示,增加类型字段和展示
新增客户端异常日志展示
通用改进
增加开发模式开关,开启后会加载一些消耗性能的检测算法
默认开启观察模式
安全基线
Tomcat 后台弱口令增加空密码检查
Path traversal
修复一处使用绝对路径下载文件,造成的 is_path_endswith_userinput 函数误报问题
拦截 Windows 下面使用 ..\..\ 列出目录的攻击
File Inclusion
修复在使用百度云BOS业务时,包含 phar:// 文件造成的误报问题
CMDi
新增常见渗透命令检测支持,默认只打印日志
SQLi
新增SQL异常检测,如语法错误、报错注入
修复 char/chr() 误报问题,仅当出现5次才报警
SSRF
调用检测插件时增加端口信息
拦截对阿里云 metadata 的访问
File Upload
报警日志增加 multipart 参数名称字段,方便构造请求
XSS
新增 xss_userinput 检测算法,拦截反射XSS
xss_echo 算法增加内容过滤,避免非攻击事件造成的报警(此算法无误报)
WebShell
拦截基于 LD_PRELOAD 的后门
Deserialization
拦截基于 JNDI 反射执行命令的攻击
管理后台
修复 docker 拉取的 ElasticSearch 无法连接的问题
PHP 版本
修复当URL没有协议,SSRF检测点拿不到hostname的问题
Java 版本
增加 okhttp/okhttp3 hook点,用于 SSRF 检测
其他通用功能
发布管理后台第一版
增加远程管理功能,包括日志上传、插件下发、远程配置管理等等
syslog 日志增加 tag 字段支持,可自定义
LRU 由插件改为agent实现,覆盖 sql, ssrf, readFile, writeFile 几个检测点
PHP 版本
正式去除 Windows 支持
命令执行
增加 JBoss EL 反射命令执行的检测
新增 bash 命令解释器,可检测命令注入攻击
修复 dubboRPC 下面,log4j 打印日志时因没有 requestMethod 导致空指针的bug
修复 PHP session + mysql handler 一处崩溃问题
修复 SpringBoot 1.5.9 + Embedded Tomcat Server 无法获取服务器版本号的问题
Java 版本
正式支持 WebSphere,目前仅测试了 8.5、9.0 两个版本
其他
报警日志增加 algorithm 字段,用于标识具体算法名称
任意文件下载
修复 ThinkPHP rewrite 导致的一个绝对路径误报问题
通用
删除SQL慢查询hook点,但暂时保留代码
Java 版本
插件获取到的 Dubbo RPC 参数名称,从 openrasp-dubbo-XXX 改为 dubbo-XXX
报警日志增加 request_method 字段,即请求方法
修复在某些 tomcat 版本下,获取参数时会产生 No modifications are allowed to a locked ParameterMap 错误的问题
Rename
修复 rename_webshell 一个潜在的误报问题
反序列化
堆栈算法增加 commons.collections4 检查
Java 版本
block.url 配置选项改名为 block.redirect_url,并支持模板化配置
即自动替换模板里的 %request_id% 关键词为当前请求ID
PHP 版本
openrasp.block_url 配置选项改名为 openrasp.block_redirect_url
并支持模板化配置,同Java版本
所有日志时间改为系统时间,不再使用PHP时区里的时间
JS API 接口
对于Java服务器,appBasePath 不再指向 webapps 目录,改为应用部署路径,比如 /tomcat/webapps/vulns
数组元素改为字典,并增加token起始坐标、token结束坐标两个参数
改进后,sqli_userinput 算法只需要再执行一遍 tokenize
Java 版本
为 JBoss 增加基线检查
当请求被拦截,且期望响应类型为 xml/json,用户可以自定义的响应内容
通过配置 block.content_xml
PHP 版本
支持通过 openrasp.hooks_ignore=all 来禁用全部 hook 点
增加获取客户端真实IP的能力,同 Java 版本
当请求被拦截,且期望响应类型为 xml/json,用户可以自定义的响应内容,同 Java 版本
增加 openrasp.plugin_filter 配置,同 Java 版本
SSRF
修复 @小猪"\ 报告的 XXE、SSRF 绕过问题,默认拦截 netloc://、jar:// 等更多不安全的协议
OGNL
hook 点改为 Ognl.topLevelExpression,以修复 @阿远 报告的 OGNL 检测报警不正确的问题
SQLi
增加懒加载和预过滤机制,仅当需要 tokenize 的时候才执行,提升性能
使用链表替换数组,优化JS LRU实现,提升性能
XXE
修复 @凌霄 反馈的 xxe_file 算法,产生大量报警日志问题
通过忽略扩展名为 dtd/xml 的实体来解决
文件目录遍历、任意文件包含
增加新的检测算法,当用户输入包含遍历特征,且用户输入位于目录结尾,判定为文件目录遍历
修复 @酒馆游侠 报告的 confluence 5.8 AFD 报警消息不正确的问题
当用户传入 file:///etc/passwd,但实际读取的是 /etc/passwd,会导致绕过,已修复
文件写入
writeFile_script 默认改成 ignore,避免大量无用日志
重命名监控
增加过滤,当源文件包含扩展名时才进入检测逻辑,以修复 @萝卜 报告的 larvael 框架下的误报问题
增加过滤,当源和目标都是文件的时候才进入检测逻辑
慢查询
由于无法获取对应的SQL语句,所以默认禁用了慢查询检测;禁用此hook点还可以提高Java版本的性能。
PHP 版本
修复 array_filter 参数处理不正确的问题
修正报警日志里, URL 字段缺少域名的问题
Java 版本
命令执行 hook 点,命令参数统一改为字符串形式
所有报警消息改为英文,下个版本增加翻译支持
PHP 版本
所有报警消息改为英文,下个版本增加翻译支持
PHP 版本
正式支持 PHP 7.0-7.2
增加对 SQL prepared statement 的支持
使用 v8 default platform 替换自定义 platform,提供更通用的后台任务能力和错误溯源能力
Java 版本
增加 rename hook 点
命令执行
增加对 FreeMarker 模板执行命令的识别
修复 @加菲猫 反馈的 cacti 误报问题
默认不再拦截所有的命令执行
PHP 版本
增加60多个单元测试,修复2处参数解析错误问题
优化不同协议的处理逻辑,若协议不支持写操作,将不再进入检测插件
修复一个左右斜杠混用,导致的路径精简失败的问题
为所有检测算法增加开关
用户可通过编辑JS插件头部的配置,来控制某个算法是否开启
ssrf_common 算法,增加对 ceye.io、transfer.sh 的检测和拦截
解决 Resin 3.1.8 一个 classloader 兼容性问题
修复 SQLParser 一处语法解析错误
通过修改包名,解决 mozilla rhino 加载冲突问题
使用v8引擎的snapshot特性,以加快v8实例启动速度
Java 版本
Java 包名改为 com.baidu.rasp
在升级前,用户需要手动删除 rasp/conf/rasp-log4j.xml 文件
SQLi 检测算法 #2,默认关闭常量对比算法
在真实业务里,经常有编码不规范的情况,会造成误报,e.g AND ((0='' OR 0='0')
命令执行检测逻辑调整
Java 版本增加 ascii banner,启动时打印
增加 JDBC Prepared SQL Hook 点
支持 Resin 3.X、4.X 服务器
增加自定义编码配置,允许用户设置 context.parameter 的编码
由 @园长MM 反馈
ProcessBuilder 存在绕过,我们将 Hook 点改为了更底层的 UNIXProcess、ProcessImpl 类
PHP 版本
当文件不存在,file_put_contents 不会调用检测插件,已修复
Java 版本
调试开关配置选项,由 debug_level 改为 debug.level
增加对 PHP 5.X 的支持
Linux 5.3 ~ 5.6
Windows 5.6 (仅线程安全版本)
Mac homebrew PHP 5.6
directory hook 点,增加 stack 参数
ssrf hook 点,增加 ip 参数
SQLi 检测算法增强
增加对 UNION NULL 语句的检测
语句规范检查算法,拦截常见盲注函数,e.g ord、chr
由 @计算姬 反馈
SQLi算法#1 - 当用户输入为纯数字时,且多次出现在SQL语句中,会产生误报,已经解决
自动安装程序
解决无法识别 JBoss 4.0.3 的问题
抓取 RASP.sql_tokenize 错误信息,并打印到 plugin.log
删除 reflection hook 点
部分框架会大量调用反射,影响性能
我们测试了一些金融业务,新版性能损耗由 10% 下降到 5%
SSRF 检测算法增强,增加更多常用域名检测
对于Java版本,SQLi/SSRF 检测算法改为Java原生实现,进一步提高性能
通过在插件修改 algorithm.config 配置来控制检测逻辑
开源协议由 BSD-3 切换为 Apache License 2.0,方便商用
支持 JBoss 7.X
支持在响应里插入 HTML 代码,可用于检测 CSRF/后台盲打,该功能默认关闭
rasp.properties 里的配置选项,除了 hooks.ignore 以外,开始支持动态更新,即修改后立即生效
拦截攻击时,支持自定义响应状态码
正式支持 SSRF 漏洞检测,包括以下三种场景
URL.openConnection
commons-httpclient
httpclient
RASP.config() 接口改名为 RASP.config_set(),并增加相关调试日志
增加 RASP.get_jsengine() 接口,用于获取JS引擎名称
解决因为没有写权限,导致 rasp-log4j.xml 释放失败的问题
在新版本里,RaspInstall 会主动修改 rasp 目录权限
安全基线日志拆分到单独的文件里
方便采集不同类型的日志
升级前,用户需要手动删除 rasp/conf/rasp-log4j.xml 文件
检测 JSTL 方式的文件包含漏洞,或者SSRF漏洞利用
支持 DB2 数据库,我们仅测试了免费版本,9.7 和 10.5
服务器安全基线
公开SQL注入检测算法 #2 - 基于语句规范,可修改插件配置
禁止多语句执行,e.g select 123; select 456
禁止16进制字符串,e.g load_file(0x41424344)
,可获取web应用根目录
,context.session.setSession、context.session.getSession
插件拆分,部分不常用的检测逻辑,比如扫描器识别功能,移动到 目录
性能优化
由于 jni 性能太差,我们决定使用 Mozilla Rhino 最新版本替换掉 j2v8
在最坏的情况下,对服务器影响在 2% 左右,具体可查看
放弃对 WebLogic 的支持
增加 SQL tokenize 接口: RASP.sql_tokenize
增加 SESSION 修改接口: context.session.getSession / context.session.setSession
readFile 接口,当文件不存在时,将不再调用插件
增加 webdav hook 点,可检查 MOVE、COPY 操作
增加 HTTP Referer 字段
增加 request_id 参数,用于标识一个攻击
增加 event_type 字段,用于标志日志类型
attack_time
支持自定义拦截页面
通过 block.url 配置
默认是
增加服务器安全基线检查功能,目前仅支持 tomcat,可以检测如下非安全配置
增加扫描器识别,根据UA、Header(默认关闭,请手动修改插件)
SQL注入检测算法 #1 开放
敏感文件下载漏洞检测
JBoss XXE Hook 点次数优化,提高性能
当JS插件发生运行时错误,不应该打印报警日志
JS插件出错时,在 plugin.log 打印详细堆栈和错误信息
增加一个异常流识别,当某些类通过反射进行调用时,会触发插件检测逻辑
增加 doFilter hook 点,修复 struts 系列框架下,无法检测漏洞的问题
支持多种 Java 服务器、数据库服务器
支持多种 SIEM 应用
完成第一版官方检测插件
支持多个 hook 点
根据自己的hook点在com.baidu.openrasp.hook包中添加一个继承自AbstractClassHook的类,并实现getType和isClassMatched两个方法进行hook点的匹配,并在hookMethod方法中的内部类的onMethodEnte方法和onMethodExit方法进行hook点前后的逻辑插入,具体代码如下:
将如上实现的hook点加入com.baidu.openrasp.transformer.CustomClassTransformer的构造方法中,实现字节码的转换,代码如下:
在 com.baidu.openrasp.plugin.checker.CheckParameter 中添加相应的检测类型
编写hook点中调用的 HookHandler.checkStringReplaceEnter 和 HookHandler.checkStringReplaceExit 方法,来实现具体的检测逻辑,检测逻辑中可以调用js插件,示例如下:
参考资料
Javassist 框架参考文档:
假设我们要新增hook_class下的hook_function方法,其对应的检测类型为hook_type,则新增HOOK过程如下:
在hook文件夹下新建新增hook点对应文件,建议命名方式为openrasp_hook_class.cc,同时将其添加至config.m4及config.w32
引入openrasp_hook.h,根据业务需求,选择合适的HOOK方式:前置HOOK(PRE_HOOK_FUNCTION_EX),后置HOOK(POST_HOOK_FUNCTION_EX)以及前后同时HOOK(HOOK_FUNCTION_EX),根据选择的HOOK方式合理定义前置处理函数及后置处理函数,形如:
JAVA_OPTS="-javaagent:\"${CATALINA_HOME}/rasp/rasp.jar\" ${JAVA_OPTS}"
JAVA_OPTS="-agentlib:jdwp=transport=dt_socket,address=1043,server=y,suspend=y ${JAVA_OPTS}"if "%ACTION%" == "start" set JAVA_OPTS="-javaagent:%CATALINA_HOME%\rasp\rasp.jar" %JAVA_OPTS%
if "%ACTION%" == "start" set JAVA_OPTS=-agentlib:jdwp=transport=dt_socket,address=1043,server=y,suspend=y %JAVA_OPTS%
2018-01-18 20:06:37,075 INFO [http-bio-8080-exec-1][com.baidu.openrasp.HookHandler] request_id=27d98d7827f04892b31bb6fe7a0fa4f0 type=request time=0
2018-01-18 20:06:37,079 INFO [http-bio-8080-exec-1][com.baidu.openrasp.HookHandler] request_id=27d98d7827f04892b31bb6fe7a0fa4f0 type=readFile time=3
2018-01-18 20:06:37,553 INFO [http-bio-8080-exec-1][com.baidu.openrasp.HookHandler] request_id=754515705fd942708efafe7c66d955be type=request time=0
2018-01-18 20:06:38,843 INFO [http-bio-8080-exec-1][com.baidu.openrasp.HookHandler] request_id=2cc0377881cd42a09868d017a276c405 type=request time=02018-07-25T16:28:14+08:00 [event-logger] 999-event-logger: 初始化成功
2018-07-25T16:28:19+08:00 [event-logger] 读取文件: /etc/hostsgdb php -ex "run -S 0.0.0.0:8123"{
"page":1,
"perpage":10,
"data":{
"version":"official-101"
}
}{
"page": 1,
"perpage": 10,
"total": 1,
"total_page": 1,
"status":0,
"description":"ok",
"data":{
"version":"official-101"
}
}{
"data": {},
"description": "ok",
"status": 0
}{
"data": {
"version": "1.3.5",
"build_time": "2020-09-02 17:35:04",
"commit_id": "055ddf48c789cd776c06c52307c716156b9f6048"
},
"description": "ok",
"status": 0
}{
"username":"openrasp",
"password":"admin@123"
}{
"data": {},
"description": "ok",
"status": 0
}{
"data": {},
"description": "ok",
"status": 0
}{
"data": {},
"description": "ok",
"status": 0
}{
"data": {
"is_default":true,
},
"description": "ok",
"status": 0
}{
"old_password":"admin@123",
"new_password":"admin*123"
}{
"data": {},
"description": "ok",
"status": 0
}{
"data": {
"id": "c593342c72eb78fc8e7393d0a87b8f3fc54dfbec8835250641a6dbd9973ae981b4b7abc4",
"app_id": "c593342c72eb78fc8e7393d0a87b8f3fc54dfbec",
"upload_time": 1542177395622,
"version": "'2018-1025-1600'",
"name": "official",
"md5": "8835250641a6dbd9973ae981b4b7abc4",
"plugin": "/*js plugin content*/",
"algorithm_config": {
"command_other": {
"action": "log"
},
"command_reflect": {
"action": "block"
},
"fileUpload_multipart_script": {
"action": "block"
},
"fileUpload_webdav": {
"action": "block"
}
},
"description": "ok",
"status": 0
}{
"id":"47af9da31ec3f233f35a25776f5e06086ebf239ff60a021ada4750b65640d0d24b9ae382"
}{
"data": {
"id": "7c70d5ba5547e77a6f9ad5d376b92fe7e47da7c4",
"app_id": "fcbc4d8ac6bcaac27b1cc4703e5339a4aa6e8a1c",
"name": "official",
"upload_time": 1546595795342,
"version": "2018-1227-1200",
"md5": "4259002c18ff3a9f40b44e91824ba0cf",
"algorithm_config": {
"xxe_file": {
"action": "log",
"name": "算法2 - 使用 file:// 协议读取文件",
"reference": "https://rasp.baidu.com/doc/dev/official.html#case-xxe"
},
"xxe_protocol": {
"action": "block",
"name": "算法1 - 使用 ftp:// 等异常协议加载外部实体",
"protocols": ["ftp", "dict", "gopher", "jar", "netdoc"]
}
... 忽略
}
},
"description": "ok",
"status": 0
}{
"id":"47af9da31ec3f233f35a25776f5e06086ebf239f3f35a25776f5e06086ebf239f",
"config":{
"xxe_file": {
"action": "log",
"name": "算法2 - 使用 file:// 协议读取文件",
"reference": "https://rasp.baidu.com/doc/dev/official.html#case-xxe"
},
"xxe_protocol": {
"action": "block",
"name": "算法1 - 使用 ftp:// 等异常协议加载外部实体",
"protocols": ["ftp", "dict", "gopher", "jar", "netdoc"]
}
... 忽略
}
}{
"data": {},
"description": "ok",
"status": 0
}{
"id":"47af9da31ec3f233f35a25776f5e06086ebf239ff60a021ada4750b65640d0d24b9ae382"
}{
"data": {},
"description": "ok",
"status": 0
}{
"id":"47af9da31ec3f233f35a25776f5e06086ebf239ff60a021ada4750b65640d0d24b9ae382"
}{
"data": {},
"description": "ok",
"status": 0
}{
"name":"Java 测试",
"language":"java",
"description":"openrasp protected",
"selected_plugin_id":"47af9da31ec3f233f35a25776f5e0608w6ebf239ff60a021ada4750b65640d0d24b9ae382"
}{
"data": {
"id": "1107158fb4cd0a901de850b2c64fab5faf0837d3",
"name": "Java 测试",
"language":"java",
"create_time":1545984191,
"secret":"SFklSJ5_DF125IKn15SDF-1SD141Af1",
"description": "openrasp protected",
"config_time": 0,
"general_config": {
"block.content.html": "</script><script>\n location.href=\"https://rasp.baidu.com/blocked2/?request_id=%request_id%\"\n </script>",
"block.content_json": "{\"error\":true,\"reason\": \"Request blocked by OpenRASP\",\"request_id\": \"%request_id%\"}",
"block.content_xml": "<?xml version=\"1.0\"?>\n\t\t\t\t\t\t\t <doc>\n\t\t\t\t\t\t\t <error>true</error>\n\t\t\t\t\t\t\t <reason>Request blocked by OpenRASP</reason>\n\t\t\t\t\t\t\t <request_id>%request_id%</request_id>\n\t\t\t\t\t\t\t </doc>",
"block.redirect_url": "https://rasp.baidu.com/blocked/?request_id=%request_id%",
"block.status_code": 302,
"body.maxbytes": 4096,
"clientip.header": "ClientIP",
"ognl.expression.minlength": 30,
"plugin.filter": true,
"plugin.maxstack": 100,
"plugin.timeout.millis": 100
},
"whitelist_config": {},
"selected_plugin_id": "",
"email_alarm_conf": {
"enable": false,
"tls_enable": false,
"server_addr": "",
"username": "",
"password": "",
"subject": "",
"recv_addr": []
},
"ding_alarm_conf": {
"enable": false,
"agent_id": "",
"corp_id": "",
"corp_secret": "",
"recv_user": [],
"recv_party": []
},
"http_alarm_conf": {
"enable": false,
"recv_addr": []
},
"attack_type_alarm_conf":null,
"algorithm_config":{}
},
"description": "ok",
"status": 0
}{
"id":"a8604735911f1866029401c6766ba87f685ff037"
}{
"data": {},
"description": "ok",
"status": 0
}{
"app_id":"569e8ea7a16123492b5878920fd36985"
}{
"app_name": "示例"
}{
"page":1,
"perpage":10
}{
"status":0,
"description":"ok",
"data":{
"id":"569e8ea7a16123492b5878920fd36985"
"name":"Java 测试",
"description":"openrasp protected",
"config_time":155536548555,
"create_time":154598419100,
"language":"java",
"general_config":{
"plugin.timeout.millis":500,
"security.enforce_policy":true,
...
}
...
}
}{
"status":0,
"description":"ok",
"page": 1,
"perpage": 10,
"total": 1,
"total_page": 1,
"data":[
{
"id":"569e8ea7a16123492b5878920fd36985"
"name":"Java 测试",
"description":"openrasp protected",
"config_time":155536548555,
"create_time":154598419100,
"language":"java",
"general_config":{
"plugin.timeout.millis":500,
"security.enforce_policy":true,
...
}
}
]
}{
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f",
"config": {
"block.content_html": "</script><script>location.href=\"https://rasp.baidu.com/blocked2/?request_id=%request_id%\"</script>",
"block.content_json": "{\"error\":true,\"reason\": \"Request blocked by OpenRASP\",\"request_id\": \"%request_id%\"}",
"block.content_xml": "<?xml version=\"1.0\"?><doc><error>true</error><reason>Request blocked by OpenRASP</reason><request_id>%request_id%</request_id></doc>",
"block.redirect_url": "https://rasp.baidu.com/blocked/?request_id=%request_id%",
"block.status_code": 403,
"body.maxbytes": 12288,
"clientip.header": "ClientIP",
"cpu.usage.enable": false,
"cpu.usage.interval": 5,
"cpu.usage.percent": 90,
"debug.level": 0,
"decompile.enable": false,
"dependency_check.interval": 100,
"fileleak_scan.interval": 21600,
"fileleak_scan.limit": 100,
"fileleak_scan.name": "\\.(git|svn|tar|gz|rar|zip|sql|log)$",
"inject.custom_headers": {
"X-Protected-By": "OpenRASP"
},
"log.maxbackup": 30,
"log.maxburst": 100,
"log.maxstack": 100,
"lru.compare_enable": false,
"lru.compare_limit": 10240,
"lru.max_size": 1000,
"ognl.expression.minlength": 30,
"plugin.filter": true,
"plugin.maxstack": 100,
"plugin.timeout.millis": 100,
"request.param_encoding": "openrasp",
"response.sampler_burst": 5,
"response.sampler_interval": 60,
"security.weak_passwords": [],
"syslog.enable": false,
"syslog.facility": 1,
"syslog.tag": "OpenRASP",
"syslog.url": ""
}
}{
"app_id":"e64071cf900944b701213a6f17d36e0d18d8b6ab",
"config":[
{
"url":"www.asod.com/sss/sss",
"hook":{
"sql":true,
"ssrf":false
},
"description":""
}
]
}{
"app_id":"47af9da31ec3f233f35a25776f5e06086ebf239f",
"attack_type_alarm_conf":{
"sql":["email","ding","http"],
"xxe":["email"]
},
"email_alarm_conf": {
"enable":false,
"tls_enable":false,
"server_addr":"email.qq.com:445",
"username":"123456789@qq.com",
"password":"4354edfwe",
"subject":"openrasp alarm",
"recv_addr":["165165@163.com"]
},
"ding_alarm_conf": {
"enable":false,
"agent_id":"1s6ef5w1ef6",
"corp_id":"1r5thnb5",
"corp_secret":"d512c5f5fg546sdg5",
"recv_user":["5sdf5","87njy7uoi"],
"recv_party":["8ik44ws"]
},
"http_alarm_conf": {
"enable":false,
"recv_addr":["www.opff.com"]
},
"general_alarm_conf":{
"alarm_check_interval":120
},
"kafka_alarm_conf":{
"url":"1.1.1.1:6666",
"user":"",
"pwd":"",
"enable":true,
"topic":"OpenRASP"
}
}{
"app_id":"47af9da31ec3f233f35a25776f5e06086ebf239f",
"name":"myapp",
"language":"php",
"description":"php应用"
}{
"app_id":"47af9da31ec3f233f35a25776f5e06086ebf239f",
"page":1,
"perpage":15
}{
"data": {
"page": 1,
"perpage": 15,
"total": 2,
"total_page": 1,
"data": [
{
"id": "47af9da31ec3f233f35a25776f5e06086ebf239ff60a021ada4750b65640d0d24b9ae382",
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f",
"upload_time": 1540992061040,
"version": "2018-1016-1000",
"md5": "f60a021ada4750b65640d0d24b9ae382"
...
},
{
"id": "47af9da31ec3f233f35a25776f5e06086ebf239f914450bbf9309777723f38facfa8183f",
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f",
"upload_time": 1540979046327,
"version": "2018-1016-0000",
"md5": "914450bbf9309777723f38facfa8183f"
...
}
]
},
"description": "ok",
"status": 0
}{
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f"
}{
"data": {
"id": "47af9da31ec3f233f35a25776f5e06086ebf239ff60a021ada4750b65640d0d24b9ae382",
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f",
"upload_time": 1540985045544,
"version": "2018-1016-1000",
"md5": "f60a021ada4750b65640d0d24b9ae382"
...
},
"description": "ok",
"status": 0
}{
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f",
"plugin_id":"47af9da31ec3f233f35a25776f5e06086ebf239ff60a021ada4750b65640d0d24b9ae382"
}{
"data": {},
"description": "ok",
"status": 0
}{
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f"
}{
"data": {},
"description": "ok",
"status": 0
}{
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f"
}{
"data": {},
"description": "ok",
"status": 0
}{
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f"
}{
"data": {},
"description": "ok",
"status": 0
}{
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f"
}{
"data": {},
"description": "ok",
"status": 0
}{
"app_id": "47af9da31ec3f233f35a25776f5e06086ebf239f"
}{
"data": {
"is_latest": false,
"selected_version": "2019-0606-1802",
"latest_version": "2019-0606-1803"
},
"description": "ok",
"status": 0
}{
"page":1,
"perpage":10,
"data": {
"id": "426199dc7a15cce89b0c937a65a24a23",
"app_id": "fcbc4d8ac6bcaac27b1cc4703e5339a4aa6e8a1c",
"version": "1.0.0-RC1",
"hostname": "820c2691f452",
"register_ip": "172.17.0.2",
"language": "java",
"language_version": "1.7.0_17",
"server_type": "tomcat",
"server_version": "7.0.78.0",
"rasp_home": "/tomcat/rasp",
"plugin_version": "2018-1227-1200",
"heartbeat_interval": 180,
"online": false,
"register_time": 1546595808,
"host_type": "docker"
}
}{
"data": {
"page": 1,
"perpage": 10,
"total": 2,
"total_page": 1,
"data": [
{
"id": "426199dc7a15cce89b0c937a65a24a23",
"app_id": "fcbc4d8ac6bcaac27b1cc4703e5339a4aa6e8a1c",
"version": "1.0.0-RC1",
"hostname": "820c2691f452",
"register_ip": "172.17.0.2",
"language": "java",
"language_version": "1.7.0_17",
"server_type": "tomcat",
"server_version": "7.0.78.0",
"rasp_home": "/tomcat/rasp",
"plugin_version": "2018-1227-1200",
"heartbeat_interval": 180,
"online": false,
"last_heartbeat_time": 1546597790,
"register_time": 1546595808,
"host_type": "docker",
"environ": {
"COLORTERM": "gnome-terminal",
"DISPLAY": ":0",
}
]
},
"description": "ok",
"status": 0
}{
"data":{
"app_id":"fcbc4d8ac6bcaac27b1cc4703e5339a4aa6e8a1c",
"version":"1.3.0"
},
"page":1,
"perpage":10
}{
"data": {
"data": [
{
"version": "1.3.0",
"count": 1
}
],
"page": 1,
"perpage": 10,
"total": 1,
"total_page": 1
},
"description": "ok",
"status": 0
}{
"app_id":"94892d14c8f1dfcedb63af258cc008929c3ef4f5",
"id": "47af9da31ec3f233f35a25776f5e06086ebf239f",
"register_ip":"126.23.3.63",
"expire_time": 604800,
"host_type": "docker"
}{
"data": {
"count":1
},
"description": "ok",
"status": 0
}{
"app_id":"94892d14c8f1dfcedb63af258cc008929c3ef4f5",
"ids": [
"47af9da31ec3f233f35a25776f5e06086ebf239f",
"d64g58d4gc3fs58745sdfgd5g5s7f54e5f4s585s",
"net1d5ns8bad6584thg1s5dnbs8gbs8af5RFG415"
]
}{
"data": {
"count":1
},
"description": "ok",
"status": 0
}{
"id": "47af9da31ec3f233f35a25776f5e06086ebf239f",
"description": "this is a description"
}{
"data": {
},
"description": "ok",
"status": 0
}{
"data":{
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a"
},
"page":1,
"perpage":10
}{
"data": {
"page": 1,
"perpage": 10,
"total": 1,
"total_page": 1,
"data": [
{
@timestamp: 1579597454365,
app_id: "4a335d670ec7c9353d3cf7480e68614dda087ded",
hostname: "d2e69eebfa7b",
id: "d1dd52ff8c82becccf9678b6ed09eca0",
path: ["/tomcat/bin/bootstrap.jar"],
product: "Apache Tomcat Bootstrap",
rasp_count: 1,
rasp_id: "3089c8d2672efd1ef5c3e322d9e8fcb1",
register_ip: "172.17.0.2",
search_string: "Apache Tomcat Bootstrap8.0.5",
source: "manifest_implementation",
tag: "Apache Software Foundation:Apache Tomcat Bootstrap:8.0.5",
vendor: "Apache Software Foundation",
version: "8.0.5"
}
]
},
"description": "ok",
"status": 0
}{
"data":{
"app_id":"0d46b13c2f25722e542b1a89817e1163e190fce1",
"tag":"org.apache.struts.xwork:xwork-core:2.3.14.2",
"key_word":"",
"hostname":""
},
"page":1,
"perpage":10
}{
"data": {
"page": 1,
"perpage": 10,
"total": 1,
"total_page": 1,
"data": [
{
@timestamp: 1579612005801,
app_id: "0d46b13c2f25722e542b1a89817e1163e190fce1",
hostname: "cq02-scloud-docker-trial",
id: "148f69b483fff233ee4d4f9fffbfd478",
path: ["/tomcat/bin/bootstrap.jar"],
product: "xwork-core",
rasp_count: 1,
rasp_id: "3089c8d2672efd1ef5c3e322d9e8fcb1",
register_ip: "10.58.119.17",
search_string: "Apache Tomcat Bootstrap8.0.5",
source: "manifest_implementation",
tag: "Apache Software Foundation:Apache Tomcat Bootstrap:8.0.5",
vendor: "Apache Software Foundation",
version: "2.3.14.2"
}
]
},
"description": "ok",
"status": 0
}{
"description":"xxx 认证 token"
}{
"token":"44b2b50665c9f11c73090b19c3dd787031611e80",
"description":"啄木鸟微服务认证token"
}{
"data": {
"token": "44b2b50665c9f11c73090b19c3dd787031611e80",
"description": "扫描器"
},
"description": "ok",
"status": 0
}{
"page":1,
"perpage":10
}{
"data": {
"page": 1,
"perpage": 10,
"total": 5,
"total_page": 1,
"data": [
{
"token": "349532e57aa36ee9b72a62fec8907109a016f348",
"description": "a token"
},
{
"token": "f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"description": "b token"
}
]
},
"description": "ok",
"status": 0
}{
"token":"f284baaeb786a8285bd1dde04a3dd7502c766c8a"
}{
"data": {
},
"description": "ok",
"status": 0
}{
"data":{
"id": "389fdbeb0aceb154d5d5d26eba28fea9f402c945",
"type_id": 1010,
"app_id": "e64071cf900944b701213a6f17d36e0d18d8b6ab",
"user": "admin",
"ip": "127.0.0.1"
},
"start_time":1,
"end_time":1542807647000,
"page":1,
"perpage":15
}{
"data": {
"data": [
{
"id": "389fdbeb0aceb154d5d5d26eba28fea9f402c945",
"type_id": 1010,
"app_id": "e64071cf900944b701213a6f17d36e0d18d8b6ab",
"time": 1542807647000,
"user": "admin",
"content": "uploaded the plugin: ba41c57afab600c39dba7398987b159d648d0836",
"ip": "127.0.0.1"
}
],
"page": 1,
"perpage": 15,
"total": 1,
"total_page": 1
},
"description": "ok",
"status": 0
}{
"data":{
"panel_url":"126.56.23.5:8086",
"agent_url":[
"126.56.23.5:8086",
"10.23.36.122:8086",
"172.23.233.192:8086"
]
},
"description": "ok",
"status": 0
}{
"panel_url":"126.56.23.5:8086",
"agent_urls":[
"126.56.23.5:8086",
"10.23.36.122:8086",
"172.23.233.192:8086"
]
}{
"data":{
"panel_url":"126.56.23.5:8086",
"agent_urls":[
"126.56.23.5:8086",
"10.23.36.122:8086",
"172.23.233.192:8086"
]
},
"description": "ok",
"status": 0
}{
"app_id":"e64071cf900944b701213a6f17d36e0d18d8b6ab"
}{
"data": {},
"description": "ok",
"status": 0
}{
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"start_time":1523264521321212,
"end_time":1523267821321000,
"interval":"hour",
"time_zone":"+08:00"
}{
"data":[
{
"start_time":1523264521321212,
"request_sum":10000
},
{
"start_time":1523264521340000,
"request_sum":87
}
],
"description": "ok",
"status": 0
}{
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"start_time":1535600036,
"end_time":1546140836,
"interval":"month",
"time_zone":"+08:00"
}{
"data": {
"data": [
[
0,
0,
0,
1,
0
],
[
0,
0,
0,
0,
0
]
],
"labels": [
1533052800000,
1535731200000,
1538323200000,
1541001600000,
1543593600000
]
},
"description": "ok",
"status": 0
}{
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"start_time":1535600036,
"end_time":1546140836,
"size":10
}{
"data":[
[
"sql", 156
],
[
"xxe", 156
]
],
"description": "ok",
"status": 0
}{
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"start_time":1535600036,
"end_time":1546140836,
"size":10
}{
data:[
[
"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36", 156
],
[
"Chrome/5.0 (X11; Linux x86_64) AppleWebKit/537.36", 156
]
],
"description": "ok",
"status": 0
}{
"data":{
"attack_type":["directory","sql"],
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"start_time":1523264521321,
"end_time":1523264521421
}
"page":1,
"perpage":10
}{
"data": {
"page": 1,
"perpage": 10,
"total": 500,
"total_page": 50,
"data":[
{
"attack_type":"directory",
"stack_md5":"1111121637821204cwwd2e52d62d0aa8",
"event_time":"2019-01-27T23:51:15+0800",
...
}
...
]
},
"description": "ok",
"status": 0
}{
"data":{
"attack_type":["directory","sql"],
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"start_time":"1523264521321",
"end_time":"1523264521421"
}
"page":1,
"perpage":10
}{
"data": {
"page": 1,
"perpage": 10,
"total": 500,
"total_page": 50,
"data":[
{
"attack_type":"directory",
"intercept_state":"block",
"plugin_confidence":100
...
}
...
]
},
"description": "ok",
"status": 0
}{
"data":{
"_id": "3456789cb45678",
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"start_time":"1523264521321",
"end_time":"1523264521421",
"hostname": "127.0.0.1",
"language": "java",
"rasp_id": "3089c8d2672efd1ef5c3e322d9e8fcb1",
"crash_message": "crash"
},
"page":1,
"perpage":10
}{
"data": {
"page": 1,
"perpage": 10,
"total": 500,
"total_page": 50,
"data":[
{
"language":"PHP",
... // 此处省略
},
... // 此处省略
]
},
"description": "ok",
"status": 0
}{
"data":{
"policy_id":["3004","3003"],
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"server_hostname":"nmg01.xx.cq",
"local_ip":"172.36.2.6",
"start_time":"1523264521321",
"end_time":"1523264521421"
},
"page":1,
"perpage":10
}{
"data": {
"page": 1,
"perpage": 10,
"total": 500,
"total_page": 50,
"data":[
{
"policy_id":"3004",
... // 此处省略
},
... // 此处省略
]
},
"description": "ok",
"status": 0
}{
"data":{
"app_id":"f284baaeb786a8285bd1dde04a3dd7502c766c8a",
"server_hostname":"nmg01.xx.cq",
"local_ip":"172.36.2.6",
"start_time":"1523264521321",
"end_time":"1523264521421"
},
"page":1,
"perpage":10
}{
"data": {
"page": 1,
"perpage": 10,
"total": 500,
"total_page": 50,
"data":[
{
"message": "HTTP request to http://scloud.baidu.com:8086/v1/agent/rasp failed:",
"server_nic": [{
"name": "en0",
"ip": "172.24.182.127"
}],
"stack_trace": "sun.reflect.NativeConstructorAccessorImpl.newInstance0(NativeMethod)",
"level": "WARN",
"event_time": "2019-01-11T13:36:46+0800",
"app_id": "9b3554a97673f1f8f5c929310298037a660d3b7a",
"pid": 58353,
"server_hostname": "localhost",
"rasp_id": "3089c8d2672efd1ef5c3e322d9e8fcb1"
}
]
},
"description": "ok",
"status": 0
}{
"id":"569e8ea7a16123492b5878920fd36985",
"version" :"v3.2",
"hostname":"tyy-OptiPlex-9020",
"register_ip":"127.56.23.4",
"language" :"java",
"language_version":"8.1" ,
"server_type":"tomcat",
"server_version":"8.5.1" ,
"heartbeat_interval":60,
"rasp_home":"/home/work/tomcat8/rasp",
"host_type":"docker",
"environ":{
"JAVA_HOME":"/home/java/jdk-7.0.25"
}
}{
"status":0,
"description":"ok",
"data":{
"id":"569e8ea7a16123492b5878920fd36985",
"app_id":"023e68ea7a12564492b5878920fd630c8",
"version" :"v3.2",
"hostname":"tyy-OptiPlex-9020",
"register_ip":"127.56.23.4",
"language" :"java",
"language_version":"8.1" ,
"server_type":"tomcat",
"server_version":"8.5.1" ,
"heartbeat_interval":60,
"rasp_home" :"/home/work/tomcat8/rasp",
"last_heartbeat_time":"15425645253",
"online":true,
"host_type":"docker",
"plugin_version":"",
"plugin_name":"",
"plugin_md5":"",
"environ":{
"JAVA_HOME":"/home/java/jdk-7.0.25"
},
"register_time":"15425645253"
}
}{
"rasp_id":"47af9da31ec3f233f35a25776f5e06086ebf239f",
"plugin_md5":"47af9da31ec3f2ebf239f",
"plugin_version":"2018-08-15 11:11:12",
"config_time":1536302712000,
"hostname":"rasp-host"
}{
"status":0,
"description":"ok",
"data":{
"plugin":{
"version":"2018-08-15 11:11:12"
"md5":"569e8ea7a16123492b5878920fd36985",
"plugin":"/*javascript*/"
},
"config_time":1536303412000,
"config":{
"block.content_html": "</script><script>location.href=\"https://rasp.baidu.com/blocked2/?request_id=%request_id%\"</script>",
"block.content_json": "{\"xxxx\":\"xxxxxx\"}",
"block.content_xml": "<?xml version=\"1.0\"?><doc><error>true</error><reason>Request blocked by OpenRASP</reason><request_id>%request_id%</request_id></doc>",
"block.redirect_url": "https://rasp.baidu.com/blocked/?request_id=%request_id%",
"block.status_code": 302,
"body.maxbytes": 4096,
"clientip.header": "ClientIP",
"debug.level": 0,
"decompile.enable": true,
"inject.custom_headers": {},
"log.maxbackup": 30,
"log.maxburst": 100,
"ognl.expression.minlength": 30,
"plugin.filter": true,
"plugin.maxstack": 100,
"plugin.timeout.millis": 100,
"syslog.enable": false,
"syslog.facility": 1,
"syslog.tag": "OpenRASP",
"syslog.url": "",
"hook.white":{
"www.test.com/test1":[sql,ssrf],
"www.test.com/test2":[sql,ssrf],
"*":[all]
}
}
}
}{
"rasp_id":"569e8ea7a16123492b5878920fd36985",
"time":15665422321,
"request_sum":10000
}{
"status":0,
"description":"ok",
"data":{}
}{
"status":0,
"description":"ok",
"data":{}
}[
{
"rasp_id":"545e8336cf5b612f358ae51ff0466476",
"app_id":"5f1b8ba39b85e2f857f6b219156470e648fd2b4f",
"server_nic": [{
"name": "cscotun0",
"ip": "172.23.232.63"
}, {
"name": "vmnet8",
"ip": "172.16.75.1"
}, {
"name": "docker0",
"ip": "172.17.0.1"
}, {
"name": "eno1",
"ip": "172.20.94.78"
}],
"event_type": "attack",
"attack_source": "127.0.0.1",
"attack_type": "command",
"plugin_name": "official",
"url": "http://127.0.0.1:8396/vulns/004-command-1.jsp?cmd\u003dcp+/etc/passwd+/tmp/",
"header": {
"cookie": "JSESSIONID\u003dF11746396310A9E88FF1C44F98B958EE; ADMINCONSOLESESSION\u003dv165dQlfGTrfpxDBdDkhTHmqVR2gYbMP57pJyRvyKsD4RcTC12N0!2052002414; JSESSIONID\u003dTkSZdRVGCnpRjYwp15dtrlnZRcFrq2q2qQ2H1fchYLstJX1BkvpF!-354254474",
"connection": "keep-alive",
"accept-language": "zh,en-US;q\u003d0.9,en;q\u003d0.8,zh-CN;q\u003d0.7",
"host": "127.0.0.1:8396",
"sec-fetch-mode": "navigate",
"accept": "text/html,application/xhtml+xml,application/xml;q\u003d0.9,image/webp,image/apng,*/*;q\u003d0.8,application/signed-exchange;v\u003db3",
"user-agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Ubuntu Chromium/76.0.3809.87 Chrome/76.0.3809.87 Safari/537.36",
"accept-encoding": "gzip, deflate, br",
"referer": "http://127.0.0.1:8396/vulns/004-command-1.jsp",
"sec-fetch-site": "same-origin",
"upgrade-insecure-requests": "1"
},
"server_type": "tomcat",
"client_ip": "",
"server_hostname": "tyy-work",
"source_code": "",
"request_method": "get",
"plugin_confidence": 90,
"request_id": "d65f0a1cf2e24951b3eb34ed25378e75",
"intercept_state": "block",
"server_version": "8.5.30.0",
"server_ip": "127.0.0.1",
"attack_params": {
"command": "cp /etc/passwd /tmp/",
"stack": ["java.lang.UNIXProcess.\u003cinit\u003e", "java.lang.ProcessImpl.start", "java.lang.ProcessBuilder.start", "java.lang.Runtime.exec", "java.lang.Runtime.exec", "java.lang.Runtime.exec", "org.apache.jsp._004_002dcommand_002d1_jsp._jspService", "org.apache.jasper.runtime.HttpJspBase.service", "javax.servlet.http.HttpServlet.service", "org.apache.jasper.servlet.JspServletWrapper.service", "org.apache.jasper.servlet.JspServlet.serviceJspFile", "org.apache.jasper.servlet.JspServlet.service", "javax.servlet.http.HttpServlet.service", "org.apache.catalina.core.ApplicationFilterChain.internalDoFilter", "org.apache.catalina.core.ApplicationFilterChain.doFilter", "org.apache.tomcat.websocket.server.WsFilter.doFilter", "org.apache.catalina.core.ApplicationFilterChain.internalDoFilter", "org.apache.catalina.core.ApplicationFilterChain.doFilter", "org.apache.catalina.core.StandardWrapperValve.invoke", "org.apache.catalina.core.StandardContextValve.invoke", "org.apache.catalina.authenticator.AuthenticatorBase.invoke", "org.apache.catalina.core.StandardHostValve.invoke", "org.apache.catalina.valves.ErrorReportValve.invoke", "org.apache.catalina.valves.AbstractAccessLogValve.invoke", "org.apache.catalina.core.StandardEngineValve.invoke", "org.apache.catalina.connector.CoyoteAdapter.service", "org.apache.coyote.http11.Http11Processor.service", "org.apache.coyote.AbstractProcessorLight.process", "org.apache.coyote.AbstractProtocol$ConnectionHandler.process", "org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun", "org.apache.tomcat.util.net.SocketProcessorBase.run", "java.util.concurrent.ThreadPoolExecutor.runWorker", "java.util.concurrent.ThreadPoolExecutor$Worker.run", "org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run", "java.lang.Thread.run"]
},
"plugin_message": "WebShell detected - Executing command: cp /etc/passwd /tmp/",
"path": "/vulns/004-command-1.jsp",
"target": "127.0.0.1",
"event_time": "2019-08-13T20:24:51+0800",
"plugin_algorithm": "command_userinput",
"body":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
]{
"status":0,
"description":"ok",
"data":{
"count":1
}
}{
"dependency": [{
"product": "rasp-engine",
"version": "1.3.0",
"vendor": "com.baidu.openrasp",
"path": "/home/work/rasp/rasp-engine.jar",
"source": "pom"
}, {
"product": "rasp-engine",
"version": "7.0.78",
"vendor": "Apache Software Foundation",
"path": "/home/work/rasp/rasp-engine.jar",
"source": "manifest_implementation"
}, {
"product": "Bootstrap",
"version": "7.0.78",
"vendor": "Apache Software Foundation",
"path": "/home/work/rasp/bin/bootstrap.jar",
"source": "manifest_implementation"
}],
"rasp_id": "3089c8d2672efd1ef5c3e322d9e8fcb1"
}{
"data": {
},
"description": "ok",
"status": 0
}[
{
"app_id": "fcbc4d8ac6bcaac27b1cc4703e5339a4aa6e8a1c",
"rasp_id": "426199dc7a15cce89b0c937a65a24a23",
"event_time": "2019-01-04T09:56:48+0000",
"event_type": "security_policy",
"message": "Java security baseline - should not start application server with root account",
"policy_id": "3002",
"policy_params": {
"pid": 431,
"stack":["java.lang.UNIXProcess.\u003cinit\u003e", "java.lang.ProcessImpl.start", "java.lang.ProcessBuilder.start", "java.lang.Runtime.exec", "java.lang.Runtime.exec", "java.lang.Runtime.exec", "org.apache.jsp._004_002dcommand_002d1_jsp._jspService", "org.apache.jasper.runtime.HttpJspBase.service", "javax.servlet.http.HttpServlet.service", "org.apache.jasper.servlet.JspServletWrapper.service", "org.apache.jasper.servlet.JspServlet.serviceJspFile", "org.apache.jasper.servlet.JspServlet.service", "javax.servlet.http.HttpServlet.service", "org.apache.catalina.core.ApplicationFilterChain.internalDoFilter", "org.apache.catalina.core.ApplicationFilterChain.doFilter", "org.apache.tomcat.websocket.server.WsFilter.doFilter", "org.apache.catalina.core.ApplicationFilterChain.internalDoFilter", "org.apache.catalina.core.ApplicationFilterChain.doFilter", "org.apache.catalina.core.StandardWrapperValve.invoke", "org.apache.catalina.core.StandardContextValve.invoke", "org.apache.catalina.authenticator.AuthenticatorBase.invoke", "org.apache.catalina.core.StandardHostValve.invoke", "org.apache.catalina.valves.ErrorReportValve.invoke", "org.apache.catalina.valves.AbstractAccessLogValve.invoke", "org.apache.catalina.core.StandardEngineValve.invoke", "org.apache.catalina.connector.CoyoteAdapter.service", "org.apache.coyote.http11.Http11Processor.service", "org.apache.coyote.AbstractProcessorLight.process", "org.apache.coyote.AbstractProtocol$ConnectionHandler.process", "org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun", "org.apache.tomcat.util.net.SocketProcessorBase.run", "java.util.concurrent.ThreadPoolExecutor.runWorker", "java.util.concurrent.ThreadPoolExecutor$Worker.run", "org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run", "java.lang.Thread.run"]
},
"server_hostname": "820c2691f452",
"server_nic": [{
"ip": "172.17.0.2",
"name": "eth0"
}],
"server_type": "tomcat",
"server_version": "7.0.78.0"
}
]{
"status":0,
"description":"ok",
"data":{
"count":1
}
}[
{
"message": "HTTP request to http://scloud.baidu.com:8086/v1/agent/rasp failed:",
"server_nic": [{
"name": "en0",
"ip": "172.24.182.127"
}],
"stack_trace": "sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)\nsun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)\nsun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)\njava.lang.reflect.Constructor.newInstance(Constructor.java:526)\nsun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1676)\nsun.net.www.protocol.http.HttpURLConnection$6.run(HttpURLConnection.java:1674)\njava.security.AccessController.doPrivileged(Native Method)\nsun.net.www.protocol.http.HttpURLConnection.getChainedException(HttpURLConnection.java:1672)\nsun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1245)\ncom.baidu.openrasp.cloud.CloudHttp.request(CloudHttp.java:64)\ncom.baidu.openrasp.cloud.Register$RegisterThread.run(Register.java:54)\njava.lang.Thread.run(Thread.java:745)\n",
"level": "WARN",
"event_time": "2019-01-11T13:36:46+0800",
"app_id": "9b3554a97673f1f8f5c929310298037a660d3b7a",
"pid": 58353,
"server_hostname": "localhost",
"rasp_id": "3089c8d2672efd1ef5c3e322d9e8fcb1"
}
]{
"status":0,
"description":"ok",
"data":{
"count":1
}
}{
"status":0,
"description":"ok"
}{
"order":"startTask",
"data":{
.....
}
}{
"data":{
"data":{
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
},
"description":"ok",
"register":2,
"status":0
},
"description":"ok",
"status":0
}{
"data":{
"version":"1.3"
},
"description":"ok",
"status":0
}{
"order":"startTask",
"data":{
"host":"1.2.3.4",
"port": 80,
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
}
}{
"data":{
"data":{
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
},
"description":"ok",
"register":2,
"status":0
},
"description":"ok",
"status":0
}{
"order":"setConfig",
"data":{
"host":"1.2.3.4",
"port":80,
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec",
"config":{
"scan_plugin_status":{
"command_basic":{
"description":"基础命令注入漏洞检测插件",
"enable":true,
"show_name":"命令注入检测插件"
},
...
},
"scan_rate":{
"max_concurrent_request":20,
"max_request_interval":1000,
"min_request_interval":0
},
"white_url_reg":"^/path/eg",
"scan_proxy":"http://127.0.0.1:8080"
}
}
}{
"data":{
"data":{
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
},
"description":"ok",
"register":2,
"status":0
},
"description":"ok",
"status":0
}{
"order":"getConfig",
"data":{
"host":"1.2.3.4",
"port": 80,
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
}
}{
"data":{
"data":{
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec",
"scan_plugin_status":{
"command_basic":{
"enable":true,
"show_name":"命令注入检测插件",
"description":"xxxx"
}
},
"scan_rate":{
"max_concurrent_request":10,
"max_request_interval":1000,
"min_request_interval":0
},
"white_url_reg":"^/logout"
},
"description":"ok",
"register":2,
"status":0
},
"description":"ok",
"status":0
}{
"order":"stopTask",
"data":{
"scanner_id":0,
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
}
}{
"data":{
"data":{
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
},
"description":"ok",
"register":2,
"status":0
},
"description":"ok",
"status":0
}{
"order":"getAllTasks",
"data":{
"page":1,
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
}
}{
"status":0,
"description":"ok",
"data":{
"total":0,
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec",
"result":[
{
"host":"127.0.0.1",
"port":8010,
"total":2,
"scanned":0,
"failed":0,
"last_time":1571303703
}
]
}
}{
"order":"cleanTask",
"data":{
"host":"1.2.3.4",
"port":80,
"url_only":true,
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
}
}{
"data":{
"data":{
"app_id":"593342c72eb78fc8e7393d0a87b8f3fc54dfbec"
},
"description":"ok",
"register":2,
"status":0
},
"description":"ok",
"status":0
}QPS
89.2
86.3
-3.25%
响应时间
1.33s
1.406s
TPS
2062
2026
-1.74%
响应时间
0.0039s
0.004s
QPS
280
269
-3.9%
响应时间
100ms
105ms
QPS
20550
20200
-1.7%
响应时间
233ms
237ms
-1.72%
QPS
55.09
54.02
-1.94%
响应时间
1.43s
1.46s
-2.1%
data
请求结果具体数据
algorithm_config
插件内的算法配置
plugin
插件内容
algorithm_config
插件内的算法配置
APP 描述信息
selected_plugin_id
String
否
APP 下发的插件
config_time
上一次下发 RASP 相关配置的时间
general_config
通用配置,用于给 RASP 下发
whitelist_config
拦截白名单配置,用于给 RASP 下发
selected_plugin_id
被选中下发的插件 id
email_alarm_conf
email 报警配置
ding_alarm_conf
钉钉报警配置
http_alarm_conf
http 报警配置
attack_type_alarm_conf
如果没有该配置,那么将会按照所有攻击类型会触发所有的报警方式,配置中的 key 是攻击类型,value 是该类型会触发的报警方式的列表,目前报警方式包括 ding,http,email
algorithm_config
app 当前选中插件的算法配置
分页页码
perpage
int
否
每页数据条数
邮件报警配置
ding_alarm_conf
Object
否
钉钉报警配置
http_alarm_conf
Object
否
http 报警配
email_alarm_conf.enable
bool
否
email 报警开关,默认 false
email_alarm_conf.tls_enable
bool
否
是否打开 邮件 tls 认证,默认 false
email_alarm_conf.server_addr
String
是
邮件服务器地址
email_alarm_conf.username
String
否
邮件账号用户名
email_alarm_conf.password
String
否
邮件账号密码
email_alarm_conf.subject
String
否
邮件主题
email_alarm_conf.recv_addr
String Array
是
邮件报警发送的邮件地址
ding_alarm_conf.enable
bool
否
钉钉报警开关,默认 false
ding_alarm_conf.agent_id
String
是
钉钉报警应用 Agent ID
ding_alarm_conf.corp_id
String
是
钉钉报警的企业 ID
ding_alarm_conf.corp_secret
String
是
钉钉报警的企业秘钥
ding_alarm_conf.recv_user
String Array
否
钉钉报警接收的用户列表,列表每个元素是一个用户的ID,不能和 recv_party 参数同时为空
ding_alarm_conf.recv_party
String Array
否
钉钉报警接收的部门列表,列表每个元素是一个部门的ID,不能和 recv_user 参数同时为空
http_alarm_conf.enable
String
否
HTTP 报警推送开关,默认false
http_alarm_conf.recv_addr
String Array
是
HTTP 报警接收地址列表
general_alarm_conf.alarm_check_interval
Int
是
邮件报警间隔(应用于所有App)
kafka_alarm_conf.url
String
是
kafka服务器的地址
kafka_alarm_conf.user
String
否
kafka服务器的用户名
kafka_alarm_conf.pwd
String
否
kafka服务器的密码
kafka_alarm_conf.enable
Bool
是
是否开启kafka推送
kafka_alarm_conf.topic
String
是
写入kafka的topic名称
APP 使用的编程语言
description
String
否
APP 描述信息
单页数量
RASP 版本
hostname
String
否
RASP 所在的主机名,该字段支持模糊搜索,并同时搜索 hostname 和 register_ip 字段
register_ip
String
否
RASP 访问云控后台所使用的 IP 地址
language
String
否
编程语言
language_version
String
否
语言版本
server_type
String
否
服务器类型
server_version
String
否
服务器版本
rasp_home
String
否
RASP 安装目录
plugin_version
String
否
插件版本
heartbeat_interval
int
否
心跳间隔时间,单位:秒
online
bool
否
是否在线
register_time
int
否
注册时间,毫秒时间戳
host_type
String
否
rasp 所在的主机类型
server_type
服务器类型
server_version
服务器版本
rasp_home
RASP 安装目录
plugin_version
插件版本
heartbeat_interval
心跳间隔时间,单位:秒
online
是否在线
last_heartbeat_time
上次心跳时间,毫秒时间戳
register_time
注册时间,毫秒时间戳
host_type
主机类型,例: docker
environ
进程环境变量
注册 ip
expire_time
int
否
单位/秒,删除超时时间超过该值的 rasp
host_type
String
否
rasp 所在的主机类型
rasp_count
影响主机数量
rasp_id
类库信息所属的RASP
register_ip
RASP 所在机器 IP 地址
search_string
source
tag
vendor
厂商
version
类库的版本号
关键词
hostname
String
否
主机名称
rasp_count
影响主机数量
rasp_id
类库信息所属的RASP
register_ip
RASP 所在机器 IP 地址
search_string
source
tag
vendor
厂商
version
类库的版本号
操作日志的结束时间,毫秒时间戳
ip
操作请求发起者相对于云控后台的 IP
结束时间
interval
String
是
聚合粒度,hour小时,month月,day天
time_zone
String
是
聚合使用的时区
结束时间
interval
String
是
聚合粒度,hour小时,month月,day天
time_zone
String
是
聚合使用的时区
结束时间
size
int
是
聚合的攻击类型数目
结束时间
size
int
是
聚合的 UA 类型数目
漏洞所属的 RASP
server_hostname
String
否
漏洞发生的机器的 hostname
attack_source
String
否
攻击来源 ip
url
String
否
攻击的 url
intercept_state
String Array
否
拦截状态,可选值:block、info,数组为空则什么都不返回,没有该参数,或者参数为null,则不过滤此参数
local_ip
String
否
攻击的机器的 ip
start_time
int
是
开始时间
end_time
int
是
结束时间
所属的 RASP
server_hostname
String
否
攻击发生的机器的 hostname 或者 IP,支持模糊搜索
attack_source
String
否
攻击来源 ip,支持模糊搜索
url
String
否
攻击的 url,包含搜索,支持模糊搜索
intercept_state
String Array
否
拦截状态,可选值:block、info,数组为空则什么都不返回,没有该参数,或者参数为null,则不过滤此参数
local_ip
String
否
攻击的机器的 ip
request_id
String
否
请求 id
stack_md5
String
否
攻击栈的 MD5
plugin_message
String
否
插件返回的监测信息,支持模糊搜索
start_time
int
是
开始时间
end_time
int
是
结束时间
该字段可以多选,数组为空则什么都不返回,没有该参数,或者参数为null,则不过滤此参数
rasp_id
String
否
所属的 RASP
language
String
否
RASP 使用的开发语言
crash_message
String
否
崩溃报警信息,支持模糊搜索
start_time
int
是
开始时间
end_time
int
是
结束时间
所属的 RASP
server_hostname
String
否
机器的 hostname 或者 IP,支持模糊搜索
local_ip
String
否
机器的 ip
message
String
否
基线报警信息,支持模糊搜索
start_time
int
是
开始时间
end_time
int
是
结束时间
机器的 hostname 或 IP ,支持模糊搜索
local_ip
String
否
机器的 ip
message
String
否
搜索异常信息包含该值的异常日志,支持模糊搜索
start_time
int
是
开始时间
end_time
int
是
结束时间
RASP 所在机器的主机名
register_ip
String
是
RASP 所在机器 IP 地址
language
String
是
RASP 使用的开发语言
language_version
String
是
RASP 使用的开发语言版本
server_type
String
是
RASP 使用的服务器种类
server_version
String
是
RASP 使用的服务器版本号
heartbeat_interval
int
是
心跳间隔时间,单位:秒
rasp_home
String
否
RASP 安装目录
host_type
String
否
主机类型,如 docker
environ
String
否
服务进程环境变量
language_version
RASP 使用的开发语言版本
server_type
RASP 使用的服务器种类
server_version
RASP 使用的服务器版本号
heartbeat_interval
心跳间隔时间,单位:秒
rasp_home
RASP 安装目录
last_heartbeat_time
上次心跳时间,如果还没有心跳,就是注册时间
online
rasp 是否在线,此处该值应为 true
host_type
主机类型,如 docker
plugin_version
插件版本,注册时还没有下发插件,所以为空
plugin_name
插件名称,注册时还没有下发插件,所以为空
plugin_md5
插件内容校验和,注册时还没有下发插件,所以为空
environ
服务进程环境变量
register_time
注册的时间戳,单位:秒
当前插件的版本
config_time
int
否
后台配置的最后修改时间,如果没有该字段或者为 0,当做没有下发过配置处理,则会下发配置
hostname
String
否
主机 hostname,用于运行时更新
请求数量,默认 0
RASP 语言
hostname
String
否
主机名
版本号
vendor
String
是
厂商
path
String
是
类库依赖路径
source
String
否
来源
扫描目标端口
app_id
String
是
APP 唯一标识
扫描目标端口
app_id
String
是
APP 唯一标识
scan_plugin_status
Object
是
配置参数
scan_rate
Object
是
扫描速率设置
white_url_reg
String
否
url白名单正则
scan_proxy
String
否
扫描请求使用的http代理
扫描目标端口
app_id
String
是
APP 唯一标识
APP 唯一标识
last_time
最后收到任务的时间
扫描目标端口
url_only
Bool
是
是否仅清空url
app_id
String
是
APP 唯一标识





package com.baidu.openrasp.hook;
import com.baidu.openrasp.HookHandler;
import javassist.CannotCompileException;
import javassist.CtClass;
import javassist.NotFoundException;
import java.io.IOException;
/**
* 自定义hook点继承自AbstractClassHook
*/
public class MyHook extends AbstractClassHook {
/**
* 返回自定义的hook点类型名称
*/
@Override
public String getType() {
return "string_replace";
}
@Override
protected void hookMethod(CtClass ctClass) throws IOException, CannotCompileException, NotFoundException {
/*
* 获取要插入函数开始的代码
* 参数 "$0,$1,$2" 表示获取带插入函数的 this,第一个参数以及第二个参数
* 然后用获取的参数调用HookHandler.checkStringReplaceEnter这个静态方法
* 最后三个参数代表HookHandler.checkStringReplaceEnter方法的参数类型
*/
String srcBefore = getInvokeStaticSrc(HookHandler.class, "checkStringReplaceEnter",
"$0,$1,$2", String.class, String.class, String.class);
// 在String.replace函数开始的地方,插入刚才获取的代码片段,第三个个参数为函数签名信息
insertBefore(ctClass, "replace", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", srcBefore);
/*
* 获取要插入函数结束的代码
* 参数 "$_" 代表获取待插入函数的返回值
* 最后用获取的内容调用HookHandler.checkStringReplaceExit这个静态方法
*/
String srcAfter = getInvokeStaticSrc(HookHandler.class, "checkStringReplaceExit", "$_", String.class);
/*
* 在String.replace函数结束的地方,插入刚才获取的代码片段,第三个个参数为函数签名信息
* 最后一个参数为true代表在异常退出的地方异常会插入响应的代码段
*/
insertAfter(ctClass, "replace", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;", srcAfter, true);
}
/**
* 匹配需要hook的类名
*/
@Override
public boolean isClassMatched(String className) {
return "java.lang.String".equals(className);//该hook点hook的是java.lang.String类
}
}public CustomClassTransformer() {
hooks = new HashSet<AbstractClassHook>();
addHook(new MyHook()); // 将hook点加入transformer
}public enum Type {
// 添加相应的检测类型,checker使用JsChecker代表该hook点的参数使用js插件检测
// 除了JsChecker之外还可以根据com.baidu.openrasp.plugin.checker包下面的其他checker进行自定义checker
// 第一个参数是检测类型名称,第二个是检测使用的checker
REPLACE("replace", new JsChecker()),
String name;
Checker checker;
Type(String name, Checker checker) {
this.name = name;
this.checker = checker;
}
@Override
public String toString() {
return name;
}
}public static void checkStringReplaceEnter(String str,String regex,String replacement){
// 如下是构造参数并进入checker的操作
// 构造参数
HashMap<String, Object> param = new HashMap<String, Object>();
param.put("str",str);
param.put("regex", regex);
param.put("replacement", replacement);
// 进入第三步中设置的checker,第一个参数是检测类型名称,第二个参数是检测参数map
doCheck(CheckParameter.Type.REPLACE, param);
}#include "openrasp_hook.h"
HOOK_FUNCTION_EX(hook_function, hook_class, hook_type);
void pre_hook_class_hook_function_hook_type(OPENRASP_INTERNAL_FUNCTION_PARAMETERS)
{
//do something
...
}
void post_hook_class_hook_function_hook_type(OPENRASP_INTERNAL_FUNCTION_PARAMETERS)
{
//do something
...
}修复@killer1278反馈的NIO文件删除hook点类型错误的问题 #280
修复奇安信公司反馈的依赖库代码问题 #265
合入@jekkay的补丁,修复非HTTP攻击报警数据会被覆盖的问题 #264
合入东方通官方提供的补丁
增加TongWeb 7.X版本支持 #318
增加JNDI检测点,并增加一个阻断所有JNDI加载的算法
增加DNS检测点,并增加DNSLog域名的检测算法
安装程序增加-debuglevel参数,支持安装时修改调试级别
PHP文件上传,展示文件存储路径
增加崩溃信息展示
合并 999-event-logger 功能到官方插件,并支持后台开启
当客户端开启 HTTPS 时,修复 SunJSSE 异常
合入 @liergou9981 的补丁,增加nio支持、优化iast.js #229
对于非HTTP请求,修复报警里缺少资产IP的问题
主机搜索接口,改为批量搜索模式
支持保留插件配置,开源版本仅保留 action 字段
支持导出应用数据,并导入到商业版
支持清理离线超过N天的主机,默认是1天,可配置
修复JSON请求数据展示不正确的问题
修复当客户端时间不正确,后台不会发出报警的问题
修复弱口令基线报警,未能正确展示数据库类型的问题
Java POM 信息
PHP composer.json
补全 SQL 异常检测点
PHP 增加 PostgreSQL、SQLite 异常监控
Java 增加 PostgreSQL、SQLite、Oracle、SQLServer、HSQLDB、DB2 监控
弱口令列表支持远程下发
加强单机版配置校验
当 yaml 最外层键值无法识别时,打印日志
报警发送间隔改为前端配置
增加报警日志去重,根据请求编号、堆栈MD5、攻击类型计算
后台日志增加大小、文件数量限制,可配置
若要测试监控效果,可执行 kill -11 PID 命令触发段错误
每隔一段时间采集一次单核CPU占用率,若超过阈值且连续3次,启动熔断机制
当下次采集到的占用率低于阈值,自动恢复防护
本功能默认关闭,采集间隔、CPU占用率均可配置
修复 plugin.filter 在 include hook 点不生效的问题
修复日志推送完毕后,log4j 缓存不会清理的问题(感谢 @忆相逢 反馈)
修复当有多个文件上传时,只会处理第一个文件的问题
修复配置更新失败时,缺少详情的问题
修复 request hook 点无法拦截的问题(感谢 @Looke 反馈)
修复 cloud.X 等配置可以远程下发的问题
修复 SQL prepared statements 产生异常时,不会进入检测插件、不会记录SQL异常的问题
新增 loadLibrary_unc 算法,当要加载的类库来自 UNC 路径时拦截
启动时打印 RASP ID,方便排查
解决当 Tomcat 主动 flush() 时不会检测 XSS 的问题
同时优化了XSS检测效率
XSS 拦截时不再抛出异常(其他攻击类型还是会抛出)
解决 jacoco 的兼容性问题
加强报警搜索功能
支持检测算法高级配置选项
修复一次心跳失败后,再也不会心跳的bug
解决 Tomcat 5 下面 html 注入功能不正常的问题
修复不重启安装,卸载后心跳线程残留问题
与PHP版本统一 log.maxbackup 逻辑,配置为1时保留今天和昨天的日志
rasp-install 增加 SELinux、open_basedir 检查,避免安装后无法使用的问题
JDK 11 支持增加应用环境变量采集
加入实验性的不重启安装、不重启卸载功能,暂不支持不重启升级
删除 webshell_include 检测点,统一使用JS插件检测
block.content_json增加 plugin.filter 配置
适用于 include/rename/readFile 等 hook 点
若开启,当文件不存在时,将不会进入检测逻辑(默认开启)
增加获取客户端真实IP的能力
用户可以在 openrasp.clientip_header 指定从哪个header里获取客户端真实IP
默认是 clientip 请求头
报警日志里的字段为 client_ip
增加 Dubbo RPC 基础数据类型支持
JS 插件可以获取到RPC参数,名字为 openrasp-dubbo-X
若完全没有命令执行需求请手动修改 command_other 算法开关为 block
此开关不影响反序列化命令执行的拦截,或者其他算法的检测
SSRF
增加对特殊协议的检测,以及对应的检测开关。包括 php://、file:// 等等
用户输入匹配算法,增加对 127.X.X.X 的识别
增加 @dos_man 反馈的一个 dnslog 地址 *.tu4.org
文件目录遍历
修复一个 @Leesec 报告的 /../../ 检出绕过问题
PHP 堆栈检测算法
修复 @Ezreal 报告的一个 call\_user\_func 误报问题
后门上传检测
增加对 rename 的监控,防止通过重命名写入 webshell
SQL 注入
增加全局LRU缓存,当检测结果为 ignore 时不再重复检测,以提高性能
用户输入匹配算法,参数最短长度可配置
增加对 into outfile 的检测,并增加相应的检测开关
解决高版本 JDK 兼容性问题,ISSUE: rhino jdk8u162 兼容性问题 #98
为了降低 Hook 点开发成本,Hook 框架改为 JavaAssist
RaspInstall - OpenRASP 自动安装程序
为了支持自动卸载,我们调整了 RaspInstall.jar 的命令行参数
java -jar RaspInstall.jar -install /home/tomcat
java -jar RaspInstall.jar -uninstall /home/tomcat
适合检测 CVE-2016-8735、CVE-2018-1270 等漏洞
增加 jnotify 异常的获取
解决日志模块一处内存泄露问题
PHP 安全基线检查
INI 配置审计
数据库连接账号审计
其他 PHP 版本支持的功能
SQL 慢查询审计
测试用例增强
增加简易导航页面
统一增加可点击链接,减少对命令行的依赖
增加PHP版本性能测试报告
开放基于 docker 的自动化漏洞测试环境 - app-env-docker
SSRF 检测算法增强
当请求的URL来自用户输入,且地址是内网地址,将会被并拦截
Java - 反序列化检测
拦截通过 ysoserial 执行命令的攻击代码
PHP - 增加对中国菜刀的检测
基于堆栈识别异常,拦截文件管理器、命令执行操作
基于用户输入识别,部分样本可直接拦截,e.g <?php eval($_POST[0]); ?>
PHP - 拦截异常的回调操作,e.g array_map("system", $whatever)
具体拦截哪些回调,请参考 openrasp.callable_blacklists 默认配置
基于反射的检查,移动到 command hook 点,检测能力不变
修改 context.parameter 获取逻辑
当JSP脚本读取过参数,JS插件才能读取到。这样可以减少误报,还可以提高SQLi算法#1的性能
支持过期日志自动删除功能,默认保留最近30天日志
通过给 log4j 1.X 打补丁来实现
升级前,用户需要手动删除 rasp/conf/rasp-log4j.xml,程序会在启动时,自动生成新的
默认 400
安全基线
支持 Tomcat Directory Index 检查
预编译JS代码,启动时间由原先的 8s 下降到 3s 左右
增加调试开关,用于收集hook点进入次数、时间消耗等等
当应用使用了高权限数据库账号,方便定位具体代码
重写 catalina.sh 脚本修改逻辑,支持重复安装
在修改的配置周围,增加类似 ### BEGIN OPENRASP ### 的标记
新增数据库连接账号审计功能,e.g 使用 root 连接 mysql、使用 sa 连接 mssql 等等
增加慢查询审计功能
使用 SELECT 语句读取超过500行数据,可配置
支持 Syslog TCP 方式传输报警日志
/*!12345禁止数字常量比较操作,e.g SELECT 1 FROM dual WHERE 8778 <> 8778
禁止使用黑名单里的函数,e.g load_file,benchmark,pg_sleep, ...
event_timeattack_params 字段改为 JSON 形式(以前是字符串,需要重新配置ES mapping)
manager/html 存在弱口令
JSESSION 未开启 httpOnly
tomcat 以 root启动
默认的 webapps 没有删除
当发生攻击,插件会额外输出 confidence 字段,用于标识检测结果可靠性
所有响应增加 X-Protected-By: OpenRASP 响应头
支持 HTTP 报警推送
增加对 Jetty、JBoss 5~6 服务器的支持
增加 log.maxstack 配置选项,用于配置 alarm 日志里最大堆栈
Rhino 引擎支持将 Java 中的对象注册到 JavaScript 环境,并被 JavaScript 代码调用
若你目前还不了解 Rhino,或者不了解如何使用 Rhino 向 JavaScript 环境中注册对象,请先查看 Rhino 官方文档:https://developer.mozilla.org/en-US/docs/Mozilla/Projects/Rhino/Embedding_tutorial#Expose_Java_APIs
在 OpenRASP 中,我们注册了 stdout 对象和 sql_tokenize 方法到 JavaScript 环境中,你可以参照我们的代码编写。
代码清单:
com/baidu/openrasp/plugin/js/engine/JSStdout.java - stdout 对象实现
com/baidu/openrasp/plugin/js/engine/JSTokenizeSql.java - sql_tokenize 方法实现
com/baidu/openrasp/plugin/js/engine/JSContextFactory.java - 初始化 JavaScript 环境并注册对象
待补充
为了验证OpenRASP的漏洞检测效果,或者IAST工具的漏洞检测能力,我们提供了多个测试用例,覆盖常见高危漏洞。测试用例的部署也非常简单,复制到 webroot/webapps 目录即可。
常用镜像:
文件说明
PHP 版本
解压 php-vulns.tar.gz 到web目录,并通过浏览器访问
Java 版本
复制war包到webapps目录,等待一段时间后可通过浏览器访问。若web服务器未开启war包自动解压缩功能,可能需要重启web服务器生效。
请参考如下几篇文章:
在每个测试用例的页面里,我们都给出了正常的请求样例,以及攻击性的请求样例。你可以点击页面上的链接触发,也可以使用 curl 命令发出请求。具体请参考实际的页面:
当攻击被拦截,OpenRASP 会显示特定的拦截页面,以及当前 Request ID,事后可根据这个ID去搜索对应的攻击日志。如果你发现 OpenRASP 无法拦截攻击,很有可能是安装没有成功,请参考 文档进行排查,并检查应用启动日志是否有错误,e.g catalina.out
值得注意的是,默认我们不开启拦截,需要你关闭 系统设置 -> 防护设置 -> 将所有算法设置为「记录日志」模式 开关,保存后等待一个心跳周期生效;单机版需要参考 修改插件,才能开启拦截。
最后,若要了解报警里有哪些字段信息,请查看 文档。
请参考 这篇文章进行操作,或者使用我们的servlet版本测试用例
如果OpenRASP没有产生报警,请按照如下方法排查
确保OpenRASP引擎工作正常
检查OpenRASP是否支持你的服务器。此类问题Java环境出现较多,比如目前netty就不支持。排查方法是检查<rasp_home>/logs/rasp/rasp.log是否有[main][com.baidu.openrasp.HookHandler] detect server: XXXX字样,如果没有就是没识别到
检查日志目录是否有写权限。此类问题PHP环境出现较多,可以参考进行排查
如果是单机版,
请参考修改插件
如果是远程管理版本
打开后台,找到 系统设置 -> 防护设置
关闭总开关,即 将所有算法设置为「记录日志」模式
对于你想要开启的检测算法,改为 拦截攻击
点击保存,并等待一个心跳周期生效(也可以通过重启tomcat/php等应用服务器快速生效)
fastjson-1.2.60.war
Java
fastjson 1.2.60 RCE 漏洞
wxpay-xxe.war
Java
某支付系统 XXE 漏洞
CVE-2019-10173.war
Java
xstream 反序列化漏洞
CVE-2019-12384.war
Java
jackson-databind 反序列化漏洞
确保漏洞存在
WAF基于请求特征检测漏洞,并不关心攻击是否成功、漏洞是否存在。OpenRASP基于行为检测,只有攻击成功的时候才会产生报警,所以需要漏洞真实存在。比如,对于SQL注入漏洞,你应该优先使用sqlmap进行测试,并确保能够读取到业务数据
检查JS检测插件是否正确
如果你同时在测试IAST,请先把插件换回防护插件,即official.js
如果不是上述问题,需要手动排查原因
开启行为日志,然后检查<rasp_home>/logs/plugin/plugin.log是否有日志。
对于远程版本,可以在后台打开打印「行为日志」开关
对于单机版,请参考修改插件
如果没有相关行为日志,则说明目前Java、PHP agent不支持你的服务器。你可以提交PR或者联系我们,并提供最小测试用例
如果有行为日志,则说明目前JS插件无法防护你发起的攻击。同样,你可以联系我们,并提交最小测试用例
php-vulns.tar.gz
PHP
主要测试用例,包含十几种高危漏洞
vulns.war
Java
主要测试用例,包含十几种高危漏洞
S2-016.war
Java
Struts S2-016 漏洞
fastjson.war
Java
fastjson RCE 漏洞

