1 Star 0 Fork 0

西岳 / rhizobia_J

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
BSD-3-Clause

关于我们

Website:https://security.immomo.com
WeChat:

成员介绍

项目简介

本项目包含两部分: java安全编码规范和JAVA安全SDK,SDK介绍详见下述。

项目结构

├── LICENSE
├── README.md
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── com
    │   │       └── immomo
    │   │           └── rhizobia
    │   │               └── rhizobia_J
    │   │                   ├── base
    │   │                   │   ├── SqliSanitiser.java
    │   │                   │   └── WhiteChecker.java
    │   │                   ├── crypto
    │   │                   │   ├── AESUtils.java
    │   │                   │   ├── ECDSAUtils.java
    │   │                   │   └── RSAUtils.java
    │   │                   ├── csrf
    │   │                   │   └── CSRFTokenUtils.java
    │   │                   ├── deserialization
    │   │                   │   └── SecureObjectInputStream.java
    │   │                   ├── extra
    │   │                   │   ├── LICENSE
    │   │                   │   ├── LICENSE-CONTENT
    │   │                   │   ├── LICENSE-README
    │   │                   │   ├── codecs
    │   │                   │   │   ├── AbstractCharacterCodec.java
    │   │                   │   │   ├── AbstractCodec.java
    │   │                   │   │   ├── AbstractIntegerCodec.java
    │   │                   │   │   ├── AbstractPushbackSequence.java
    │   │                   │   │   ├── Codec.java
    │   │                   │   │   ├── DB2Codec.java
    │   │                   │   │   ├── HTMLEntityCodec.java
    │   │                   │   │   ├── HashTrie.java
    │   │                   │   │   ├── JavaScriptCodec.java
    │   │                   │   │   ├── MySQLCodec.java
    │   │                   │   │   ├── OracleCodec.java
    │   │                   │   │   ├── PushBackSequenceImpl.java
    │   │                   │   │   ├── PushbackSequence.java
    │   │                   │   │   ├── PushbackString.java
    │   │                   │   │   └── Trie.java
    │   │                   │   └── commons
    │   │                   │       ├── CollectionsUtil.java
    │   │                   │       ├── EncoderConstants.java
    │   │                   │       ├── NullSafe.java
    │   │                   │       ├── RandomCreater.java
    │   │                   │       └── StringUtilities.java
    │   │                   ├── sqli
    │   │                   │   ├── DB2Sanitiser.java
    │   │                   │   ├── MysqlSanitiser.java
    │   │                   │   └── OracleSanitiser.java
    │   │                   ├── ssrf
    │   │                   │   └── SSRFWhiteChecker.java
    │   │                   ├── urlredirection
    │   │                   │   └── UrlRedirectionWhiteChecher.java
    │   │                   ├── xss
    │   │                   │   └── XssSanitiser.java
    │   │                   └── xxe
    │   │                       └── XmlUtils.java
    │   └── resources
    │       └── log4j.properties
    └── test
        └── java
            └── com
                └── immomo
                    └── rhizobia
                        └── rhizobia_J
                            ├── AESUtilsTest.java
                            ├── CSRFTokenUtilsTest.java
                            ├── DB2SanitiserTest.java
                            ├── ECDSAUtilsTest.java
                            ├── MysqlSanitiserTest.java
                            ├── OracleSanitiserTest.java
                            ├── RSAUtilsTest.java
                            ├── SSRFWhiteCheckerTest.java
                            ├── SafeClass.java
                            ├── SecureObjectInputStreamTest.java
                            ├── TestBean.java
                            ├── UnsafeClass.java
                            ├── UrlRedirectionWhiteChecherTest.java
                            ├── XmlUtilsTest.java
                            └── XssEncoderTest.java

目录

1、引用java security library

环境需求

  • Java 8
  • Maven 3

a、编译jar包:

    mvn -Dmaven.test.skip=true clean install

b、引入java security library:

在target目录中找到target/rhizobia_J-1.0.jar,导入工程中

需要在自己的maven工程pom.xml中加入如下依赖

    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>commons-codec</groupId>
        <artifactId>commons-codec</artifactId>
        <version>1.11</version>
    </dependency>

2、SQL注入防护

a、确认是连接的是哪种数据库,选择对应的数据库编码,目前支持数据库包括:MySQL Oracle DB2:

    import com.immomo.rhizobia.rhizobia_J.sqli.MysqlSanitiser;
    //import com.immomo.rhizobia.rhizobia_J.sqli.OracleSanitiser;
    //import com.immomo.rhizobia.rhizobia_J.sqli.DB2Sanitiser;
    
    MysqlSanitiser sqlTool = MysqlSanitiser.getInstance();

b、对sql语句中拼接的参数进行转义:

    String id = "1' or '1'='1' #";
    String idEncode = sqlTool.mysqlSanitise(id);
    String query = "SELECT NAME FROM users WHERE id = '" + idEncode + "'";

使用order by、group by等需要转换列名时,需使用带boolean参数

    //保证列名中的下划线不被转义
    String columnName = "user_name";
    String columnNameEncode = sqlTool.mysqlSanitise(columnName, true);
    query = "SELECT NAME FROM users order by " + columnNameEncode ;

c、转义前后对比:

    转义前SELECT NAME FROM users WHERE id = '1' or '1'='1' #'
    转义后SELECT NAME FROM users WHERE id = '1\' or \'1\'\=\'1\' \#'

d、表名列名转义前后对比:

    转义前SELECT NAME FROM users order by user_name
    转义后SELECT NAME FROM users order by user_name
    转义前SELECT NAME FROM users order by user-name
    转义后SELECT NAME FROM users order by user\-name

3、xss防护

a、调用XssSanitiser单例:

    import com.immomo.rhizobia.rhizobia_J.xss.XssSanitiser;
    
    XssSanitiser xssFilter = XssSanitiser.getInstance();

b、如果输出到html body:

    String ret = xssFilter.encodeForHTML(oriString);

过滤前后对比:

    过滤前<script> alert('xss') </script>
    过滤后&lt;script&gt;alert&#x28;&#x27;xss&#x27;&#x29;&lt;&#x2f;script&gt;

c、如果输出到html标签的属性(多了对空字符的过滤):

    String ret = xssFilter.encodeForHTMLAttribute(oriString);

过滤前后对比:

    过滤前<script> alert('xss') </script>
    过滤后&lt;script&gt;&#x20;alert&#x28;&#x27;xss&#x27;&#x29;&#x20;&lt;&#x2f;script&gt;

d、如果输出到JavaScript代码块中:

    String ret = xssFilter.encodeForJavaScript(oriString);

过滤前后对比:

    过滤前alert('xss');
    过滤后alert\x28\x27xss\x27\x29\x3B

4、url重定向防护

a、调用UrlRedirectionWhiteChecher单例:

    import com.immomo.rhizobia.rhizobia_J.urlredirection.UrlRedirectionWhiteChecher;
    
    UrlRedirectionWhiteChecher urlChecker = UrlRedirectionWhiteChecher.getInstance();

b、自定义白名单:

    List<String> whitelist = new ArrayList<String>();
    String white1=".trust1.com";
    String white2=".trust2.com";
    
    //setWhiteList会先清空原有白名单列表
    //在原有基础上新增白名单,使用addWhiteList(whitelist)
    urlChecker.setWhiteList(whitelist);

c、校验url:

    try{
        boolean isWhite = urlChecker.verifyURL(url.trim());
    } catch (Exception e) {
        ...
    }

5、SSRF防护

a、调用SSRFWhiteChecker单例,与前面url重定向类似:

    import com.immomo.rhizobia.rhizobia_J.ssrf.SSRFWhiteChecker;
    
    SSRFWhiteChecker ssrfChecker = SSRFWhiteChecker.getInstance();

b、自定义白名单:

    List<String> whitelist = new ArrayList<String>();
    String white1=".trust1.com";
    String white2=".trust2.com";
    
    //setWhiteList会先清空原有白名单列表
    //在原有基础上新增白名单,使用addWhiteList(whitelist)
    ssrfChecker.setWhiteList(whitelist);

c、校验url:

    try{
        boolean isWhite = ssrfChecker.verifyURL(url.trim());
    } catch (Exception e) {
        ...
    }

6、CSRF防护

a、随机算出csrf token,并且每次生成随机值都不一样(实测结果连续生成1000亿次无重复):

    import com.immomo.rhizobia.rhizobia_J.csrf.CSRFTokenUtils;

    CSRFTokenUtils csrfInstance = CSRFTokenUtils.getInstance();
    String token = csrfInstance.resetCsrfToken(32);

b、后端保存生成的token,以待校验(可以采用数据库、分布存储等任意存储手段)

c、前端页面加上hidden字段

form中加入csrf token的hidden字段:

    <input name="${(_csrf.parameterName)!}" value="${(_csrf.token)!}" type="hidden">

ajax中加入csrf头

    xhr.setRequestHeader("${_csrf.headerName}", "${_csrf.token}");

d、当前端向后端发送请求时,请求header中携带token,后端收到后与之前存储的token进行校验

7、readObject反序列化漏洞防护

a、选择适当的构造函数初始化,自定义白名单:

使用SecureObjectInputStream中适当的构造函数,增加自定义的白名单

    import com.immomo.rhizobia.rhizobia_J.deserialization.SecureObjectInputStream;

    SecureObjectInputStream(InputStream in, String[] classlist)
    SecureObjectInputStream(InputStream in, List<String> classlist)

b、使用安全的类SecureObjectInputStream,恢复非白名单中类的对象时会抛出异常:

    List<String> classlist = new ArrayList<String>();
    classlist.add(SafeClass.class.toString());
    
    try{   
        //考虑如果白名单为空时会影响正常判断逻辑,所以此处会抛出异常
        SecureObjectInputStream ois = new SecureObjectInputStream(fis, classlist);
        
        //使用安全的SecureObjectInputStream恢复对象时会抛出exception
        UnsafeClass objectFromDisk = (UnsafeClass)ois.readObject();
    } catch (Exception e) {
        ...
    }

8、xxe防护

8.1、解析xml内容为Document

a、初始化时注意xml编码格式:

    import com.immomo.rhizobia.rhizobia_J.xxe.XmlUtils;
    //如果xml格式包含外部实体,会抛异常
    try{
        Document doc =  XmlUtils.getInstance().newDocument(xmlFile, "utf-8");
    } catch (Exception e) {
        ...
    }

b、使用生成的Document对象:

    Node notifyNode = doc.getFirstChild();
    NodeList list = notifyNode.getChildNodes();
    for (int i = 0, length = list.getLength(); i < length; i++) {
        Node n = list.item(i);
        String nodeName = n.getNodeName();
        String nodeContent = n.getTextContent();
        System.out.println(nodeName.toString() + "    " + nodeContent.toString());
    }

8.2、解析xml内容为Bean

a、自定义TestBean,然后调用converyToJavaBean解析:

    import com.immomo.rhizobia.rhizobia_J.xxe.XmlUtils;

    //如果xml格式包含外部实体,会抛异常
    XmlUtils xmlParser =  XmlUtils.getInstance();
    try {
        TestBean testbean = (TestBean)xmlParser.converyToJavaBean(xmlFile, TestBean.class);
    } catch (Exception e) {
        ...
    }

b、使用生成的bean对象:

    testbean.getTo()
    testbean.getFrom()
    testbean.getHeading()
    testbean.getBody()

9、AES加解密

知识点1:oracle官方已经在如下版本去除了aes-256的限制,6u181,7u171,8u161,9 b148,openjdk7u
                 https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8170157
 
知识点2:之所以AES、RSA没有封装base64或16进制编码处理,是因为在使用base64编码后的内容中,可能存在'+'字符,
              '+'字符返回给前端后再返回给后端时,如果不经过处理,会变为' '空格字符,
               所以请用户自行选择base64编码或16进制编码
               并在对加密内容进行base64编码时,请注意'+'字符

a、调用AESUtils:

    import com.immomo.rhizobia.rhizobia_J.crypto.AESUtils;
    
    AESUtils aesInstance = AESUtils.getInstance(String aesKey, String secretKey, String aesMode);
    /**
    参数说明:
        aesKey:     用于生成密钥的原始字符串,推荐使用session/id,具有唯一性
        secretKey:  加解密双方约定的secret
        aesMode:    值为null时,默认采用"AES/CBC/PKCS5Padding"
    */
    AESUtils aesInstance = AESUtils.getInstance("843739488","TcmEqGzSpH5S2VgoUix7HJ9cwqCofoUD",null);

b、加密

    String orginText = "10000";
    
    byte[] ciphertext = aesInstance.Encrypt(orginText);
    //由于返回是byte流,所以如果需要base64编码或转换成Hex,需另做处理
    String encryptRet = new BASE64Encoder().encode(ciphertext);

c、解密

    //同样,如果加密内容用base64编码或转换成Hex,解密时需另做处理
    byte[] encrypted = new BASE64Decoder().decodeBuffer(encryptRet);
    String DeString = aesInstance.Decrypt(encrypted);

10、RSA加解密 加签验签

知识点1:RSA加解密时,明文是有长度限制的,明文字符串限制长度 = 密钥长度(byte) - padding占用大小(byte)
         padding大小如下:
              RSA/ECB/PKCS1Padding or RSA             :   11
              RSA/ECB/OAEPWithSHA-1AndMGF1Padding     :   42
              RSA/ECB/OAEPWithSHA-256AndMGF1Padding   :   66
    
         例如:RSA密钥长度为1024(bit)/8 = 128(byte),keyPairGenerator.initialize(1024),
              在RSA/ECB/OAEPWithSHA-1AndMGF1Padding模式下,
              被加密的明文字符串长度不能超过 128-42 = 86
              
知识点2:同前一节aes的知识点2

知识点3:源码所用的signature类中,已经封装了摘要算法,所以可以不必再生成摘要,当然自已多生成摘要也没有问题

感谢LeadroyaL的issue

10.1、加解密

a、创建RSAUtils单例

  1. 如密钥在文件中:
    import com.immomo.rhizobia.rhizobia_J.crypto.RSAUtils;
    
    /**
    参数说明:目前证书支持 PEM 格式
        priKeyPath:  openssl生成的私钥地址
        pubKeyPath:  openssl生成的公钥地址
    */
    String priKeyPath = "/tmp/pri.key";
    String pubKeyPath = "/tmp/pub.key";
    RSAUtils rsaInstance = RSAUtils.getInstance(priKeyPath, pubKeyPath);
  1. 由于文件头尾格式有多种,根据需要调用set方法修改头尾后生成公私钥
   RSAUtils rsaInstance = RSAUtils.getInstance();
   rsaInstance.setPemPriHead("-----BEGIN PRIVATE KEY-----\n");
   rsaInstance.setPemPriEnd("-----END PRIVATE KEY-----");
   rsaInstance.setPemPubHead("-----BEGIN PUBLIC KEY-----\n");
   rsaInstance.setPemPubEnd("-----END PUBLIC KEY-----");
   rsaInstance.setPrivateKey(rsaInstance.getPrivateKey(priKeyPath));
   rsaInstance.setPublicKey(rsaInstance.getPublicKey(pubKeyPath));
  1. 如果已有公私钥,也可直接用已有密钥生成单例
    //如下为生成公私钥的例子,用户可任意选用其他方法生成公私钥
    KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
    keyPairGenerator.initialize(512);
    KeyPair keyPair = keyPairGenerator.generateKeyPair();
    PublicKey rsaPublicKey = (PublicKey) keyPair.getPublic();
    PrivateKey rsaPrivateKey = (PrivateKey) keyPair.getPrivate();
    
    //生成单例
    RSAUtils rsaInstance = RSAUtils.getInstance(rsaPrivateKey, rsaPublicKey);

b、加密

    String plaintext = "123";

    //如知识点1,如果明文长度超过最大长度,可以用rsaInstance.encryptWithouLimit
    //或者自行将明文字符串拆分成对应的限制长度的块
    byte[] ciphertext = rsaInstance.encrypt(plaintext);
    
    //与aes一样返回是byte流,所以如果需要base64编码或转换成Hex,需另做处理
    String encryptRet = new BASE64Encoder().encode(ciphertext);

c、解密

    //同样,如果加密内容用base64编码或转换成Hex,解密时需另做处理
    byte[] encrypted = new BASE64Decoder().decodeBuffer(encryptRet);

    //如知识点1,如果使用了encryptWithouLimit加密,对应使用rsaInstance.decryptWithoutLimit进行解密
    String plaintext = rsaInstance.decrypt(ciphertext);

10.2、加签验签(更推荐使用ECDSA来实现加签验签,参考)

a、加签

    //原文
    String plaintext = "123";

    byte[] sigintext = rsaInstance.sign(plaintext);
    //与aes一样返回是byte流,所以如果需要base64编码或转换成Hex,需另做处理
    String signtRet = new BASE64Encoder().encode(sigintext);

b、验签

    //同样,如果加密内容用base64编码或转换成Hex,解密时需另做处理
    byte[] verified = new BASE64Decoder().decodeBuffer(signtRet);
    boolean ifPass = rsaInstance.verify(verified, plaintext);

11、ECDSA 加签验签

a、创建ECDSAUtils单例

与前面一节RSA类似,也有三种获取单例的方法

    import com.immomo.rhizobia.rhizobia_J.crypto.ECDSAUtils;

    String priKeyPath = "/tmp/ECDSAPrivateKey.key";
    String pubKeyPath = "/tmp/ECDSAPublicKey.key";
    ECDSAUtils ecInstance = ECDSAUtils.getInstance(priKeyPath, pubKeyPath);

    //ECDSAUtils.getInstance()或ECDSAUtils.getInstance(ecPrivateKey, ecPublicKey)参照前面RSA章节

b、加签

    String plaintext = "123";

    byte[] sigintext = ecInstance.sign(plaintext);
    //与aes一样返回是byte流,所以如果需要base64编码或转换成Hex,需另做处理
    String signtRet = new BASE64Encoder().encode(sigintext);

c、验签

    //同样,如果加密内容用base64编码或转换成Hex,解密时需另做处理
    byte[] verified = new BASE64Decoder().decodeBuffer(signtRet);
    boolean ifPass = ecInstance.verify(verified, plaintext);
Copyright (c) [2019], [V0ld1ron] All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the {organization} nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

简介

暂无描述 展开 收起
BSD-3-Clause
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
1
https://gitee.com/huashan_mountain123/rhizobia_J.git
git@gitee.com:huashan_mountain123/rhizobia_J.git
huashan_mountain123
rhizobia_J
rhizobia_J
master

搜索帮助