• JAVA常见编程风险

    普通类
    • 支持
    • 批判
    • 提问
    • 解释
    • 补充
    • 删除
    • 1. 空指针引用(null pointer dereference)

    try
    {
    aAuthPortalUserEntity =new AuthPortalUserEntity();
    AuthenticateProcessIF authenticate = null;
    if(authenticateProcessId != null && authenticateProcessId.length() > 0)‏
    authenticate = AuthenticateProcessFactory.createAuthenticateProcess(Integer.parseInt(authenticateProcessId));
    if(authenticate != null)‏
    aAuthUserResult = (AuthRoamUserResult)authenticate.process(aAuthPortalUserEntity);
    else
    if(userLocation.equalsIgnoreCase("1")) (1)
    aAuthUserResult = authMgr.OWAuthPortalUser(aAuthPortalUserEntity);
    else
    if(userLocation.equalsIgnoreCase("2")) (2)
    aAuthUserResult = authMgr.OWAuthRoamVnetCenterUser(aAuthPortalUserEntity);
    }
    catch(Exception ex)‏
    {
    PMLogger.exception(“ex", ex);
    aAuthUserResult = new AuthRoamUserResult();
    aAuthUserResult.setResult("false");
    aAuthUserResult.setMessage("Parse_Request_String_erro");
    }
    String resultStr = EntityConvertor.Object2String(aAuthUserResult);
    当前面的(1)和(2)判断不满足时,会导致 aAuthUserResult为空,出现空指针引用异常。

    影响:
    导致运行时空指针异常,停止执行,暴露服务器信息
    指导意见:
    加上空指针判断

    • 2. 先使用再检查(NULL checks after dereferences)

    public ProvinceSettlementResult processProvinceSettlement(ProvinceSettlement parameters){

    String SenderID = parameters.getSenderID();
    (1)
    String TimeStamp = parameters.getTimeStamp();

    TransactionContext tc = null;

    String errormessage = null;

    RoamSettlementFeeback feeback = new RoamSettlementFeeback();

    if(parameters != null){
    (2)
    在(1)处先使用,然后在(2)处再检查是否为空
    影响:
    导致运行时空指针异常,停止执行,暴露服务器信息
    指导意见:
    开发人员应该避免养成先使用再检查的习惯,先检查指针是否为空再使用

    • 3. 资源泄露(RESOURCE LEAK)

    try {
    echoSocket = new Socket("nothing", 7); // Socket() constructor obtains socket
    out = new PrintWriter(echoSocket.getOutputStream(), true);
    in = new BufferedReader(new
    InputStreamReader(echoSocket.getInputStream()));
    } catch (UnknownHostException e) {
    System.err.println("Don't know about host: taranis.");
    return; // function returns,
    // but close() is never called on exception path
    }
    file, socket等都应该及时关闭

    IO文件流使用后没有关闭
    影响:
    资源泄露导致性能降低
    指导意见:
    使用完后关闭

    • 4. 数据库连接问题

    public void test1() throws Exception {
    Connection c = DriverManager.getConnection("foo");
    // 没有关闭连接
    }

    影响:
    资源泄露导致性能降低
    指导意见:
    使用完后关闭

    • 5. 数据库注入

    String sql = null;
    Statement stmt = null;
    Connection conn = null;
    ResultSet rs = null;
    sql = "SELECT id FROM user WHERE id='" + userName + "' and password='" + passWord + "'";

    ……

    conn = DriverManager.getConnection(,,);
    stmt = conn.createStetement();
    rs = stmt.executeQuery(sql);

    影响:
    --非法查询其他数据库资源,如管理员帐号。
    --执行系统命令
    --获取服务器root权限

    指导意见:
    应该用Preparedstatement来代替statement,这样我们就可以使用占位符作为实参来定义sql语句,从而避免sql注入的攻击:
    Connection conn = DriverManager.getConnection(url, user, password);
    String query = "select * from table_user where user_name=?";
    PreparedStatement preState = conn.prepareStatement(query);
    preState.setString(1, "aaa");
    ResultSet rs = preState.executeQuery();

    • 6. 调用低效函数(Invokes inefficient constructor)

    public static byte[] getAuthSeed(int length)
    {
    byte b[] = new byte[length];
    for(int i = 0; i < b.length; i++)
    b[i] = (byte)(int)(Math.random() * 1024D);
    return b;
    }
    应该调用nextInt来代替nextDouble
    影响:
    调用低效构造函数,浪费内存空间,降低性能
    指导意见:
    避免调用类似的低效构造函数

    • 7. 数组引用问题(RETURN ARRAY)

    某个方法返回一个对敏感对象的内部数组的引用,假定该方法的调用程序不改变这些对象。即使数组对象本身是不可改变的,也可以在数组对象以外操作数组的内容,这种操作将反映在返回该数组的对象中。如果该方法返回可改变的对象,外部实体可以改变在那个类中声明的 public 变量,这种改变将反映在实际对象中。
    public class XXX {
    private String[] xxxx;
    public String[] getXXX() {
    return xxxx;
    }
    影响:
    返回内部数组指针,可能暴露内部数据
    指导意见:
    避免直接返回内部数组指针,应该返回一个新的拷贝
    public class XXX {
    private String[] xxxx;
    public String[] getXXX() {
    String temp[] = xxxx;
    return temp;
    }

    • 8. 保存引用到不定对象 (Storing reference to mutable object)

    private UserDetailIndicator userDetailIndicator[];
    public void setUserDetailIndicator(UserDetailIndicator userDetailIndicator[])‏

    {

    this.userDetailIndicator = userDetailIndicator;
    }
    影响:
    保存引用到不定对象,可能暴露内部数据
    修复方案:
    避免直接保存引用到不定对象,应该保存一份拷贝

    • 9. 硬编码敏感数据(Hard-coded sense data)

    public static void main(String args[])
    throws Exception
    {

    String key = "FCB5023DA5545ED8680A2D07806DBDCA6ACDCF47E08F6A2D";
    String iv = "0102030405060708";
    String source = "hello=wangjununjjljlajflafja";
    byte des[] = encrypt(source, key, iv, "DESede/CBC/PKCS7Padding");
    Base64 encoder = new Base64();
    Base64 _tmp = encoder;
    String encodeBase64 = Base64.encode(des);
    System.out.println(encodeBase64);
    BASE64Decoder decoder = new BASE64Decoder();
    byte decodeBase64[] = decoder.decodeBuffer(encodeBase64);
    System.out.println(decrypt(decodeBase64, key, iv, "DESede/CBC/PKCS7Padding"));
    }
    此模块是加解密模块,main函数不会被使用到,把敏感的密钥放入到main中进行测试容易让其他开发人员也获知加解密方法,增加了泄密的安全隐患。
    影响:
    导致泄露敏感数据,增加安全隐患
    指导意见:
    将敏感数据保存在属性文件中,无论什么时候需要这些数据,都可以从该文件读取。如果数据极其敏感,那么在访问属性文件时,应用程序应该使用一些加密/解密技术。

    • 10. 无用的代码(unused code)

    无用的代码有三类:
    • 类中的 main 方法
    • 定义过且未使用的方法
    • 注释中的死代码
    影响:
    通常,开发人员往往在其类中编写 main() 方法,这有助于测试单个类的功能。当类从测试转移到生产环境时,带有 main() 方法的类就成为了对应用程序的潜在威胁,攻击者可能将它们用作入口点。
    开发人员应该检查代码中是否有未使用的方法出现。这些方法在测试期间将会通过所有的安全检查,因为在代码中不调用它们 ― 但它们可能含有硬编码在它们内部的敏感数据(虽然是测试数据)。攻击者随后可能调用这样的方法。
    同时,应该避免最终应用程序中的死代码(注释内的代码)。如果攻击者去掉了这样的代码的注释,那么代码可能会影响系统的功能性。
    指导意见:
    应该将(除启动应用程序的 main() 方法之外的) main() 方法、未使用的方法以及死代码从应用程序代码中除去。在软件交付使用之前,主要开发人员应该对敏感应用程序进行一次全面的代码评审。应该使用“Stub”或“dummy”类代替 main() 方法以测试应用程序的功能。

    • 11. 变量的访问

    如果将变量声明为public,那么外部代码就可以操作该变量。这可能会导致安全性暴露。
    影响:
    如果实例变量为 public ,那么就可以在类实例上直接访问和操作该实例变量。将实例变量声明为 protected 并不一定能解决这一问题:虽然不可能直接在类实例基础上访问这样的变量,但仍然可以从派生类访问这个变量。

    示例1. 带有 public 变量的代码
    class Test {
    public int id;
    protected String name;
    Test(){
    id = 1;
    name = "hello world";
    }
    //code
    }
    public class MyClass extends Test{
    public void methodIllegalSet(String name){
    this.name = name; // 不应该直接访问
    }
    public static void main(String[] args){
    Test obj = new Test();
    obj.id = 123; //不应该直接访问
    MyClass mc = new MyClass();
    mc.methodIllegalSet("Illegal Set Value");
    }
    }
    指导意见:
    一般来说,应该使用取值方法而不是 public 变量。按照具体问题具体对待的原则,在确定哪些变量特别重要因而应该声明为 private 时,请将编码的方便程度及成本同安全性需要加以比较。
    示例2 演示了以下列方式来使之安全的代码:
    class Test {
    private int id;
    private String name;
    Test(){
    id = 1;
    name = "hello world";
    }
    public void setId(int id){
    this.id = id;
    }
    public void setName(String name){
    this.name = name;
    }
    public int getId(){
    return id;
    }
    public String getName(){
    return name;
    }
    }

    • 12.通过名称比较类



    有时候,可能需要比较两个对象的类,以确定它们是否相同;或者,可能想看看某个对象是否是某个特定类的实例。因为 JVM 可能包括多个具有相同名称的类(具有相同名称但却在不同包内的类),所以不应该根据名称来比较类。
    影响:
    如果根据名称来比较类,可能无意中将不希望授予别人的权利授予了攻击者的类,因为攻击者可以定义与开发人员的类同名的类。
    如下面的示列演示了这一错误方法:
    if(obj.getClass().getName().equals("Vnet")) // Wrong!
    // objects class is named Vnet
    }else{
    // object's class has some other name
    }
    指导意见:
    在那些非得根据名称来比较类的情况下,必须格外小心,必须确保使用了当前类的 ClassLoader 的当前名称空间,如下面示例中所示的一种更好的比较方法:
    if(obj.getClass() == this.getClassLoader().loadClass("com.bar.Vnet")){
    // object's class is equal to
    //the class that this class calls "com.bar.Vnet"
    }else{
    // object's class is not equal to the class that
    // this class calls "com.bar.Vnet"
    }
    比较类的更好方法是直接比较类对象看它们是否相等:
    if(a.getClass() == b.getClass()){
    // objects have the same class
    }else{
    // objects have different classes
    }
    尽可能少用直接名称比较。

    • 13.正确的equals

    String myString = "test";
    if(myString.equals("TEST")) {
    //TODO
    } else {
    //TODO
    }
    影响:
    可能导致空指针异常
    修复方案:
    String myString = "test";
    if("TEST".equals(myString)) {
    //TODO
    } else {
    //TODO
    }

    • 总结

    编写完全安全 Java 代码是十分困难的,本文档描述了一些常见的编程风险和可行指导意见来帮助开发人员编写更安全的Java 代码。这些建议并不能解决所有安全性问题,但它们将减少安全缺陷,帮助并确保软件正常运行。

    • 标签:
    • 常见
    • 使用
    • string
    • 风险
    • 方法
    • java
    • public
    • 代码
    • 影响
    • 指导
    • 编程
    • 应该
    • class
    • 意见
  • 加入的知识群:
    学习元评论 (0条)

    评论为空
    聪明如你,不妨在这 发表你的看法与心得 ~



    登录之后可以发表学习元评论
      
暂无内容~~
顶部