Java 开发安全规范.docx_第1页
Java 开发安全规范.docx_第2页
Java 开发安全规范.docx_第3页
Java 开发安全规范.docx_第4页
Java 开发安全规范.docx_第5页
免费预览已结束,剩余16页可下载查看

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java 开发安全规范目 录一. 安全隐患11.1 ProcessBuilder注入允许攻击者执行代码11.2 确保public和static字段被定义为final11.3 包含敏感调用的方法应标记为final21.4 执行数据库查询前设置查询类型31.5 实现Serializable接口时没有定制序列化协议31.6 限制特权代码的可访问性41.7 确保SecurityManager权限检查的完整性61.8 避免在public方法中返回private内部数据81.9 避免危险的public static final数组声明8二. 环境配置92.1 不要将多类URL映射到同一个Servlet92.2 不要在配置文件中存放敏感信息92.3 确保Servlet有名字并正确配置102.4 限制字段最大长度避免DoS或注入攻击11三. 代码质量123.1 谨慎使用Thread.yield()方法123.2 使用notifyAll方法替代notify133.3 避免使用Thread的stop方法133.4 重新抛出ThreadDeath异常133.5 确保锁在发生异常时被正确释放143.6 避免在获取锁后调用sleep方法163.7 避免在finally块中抛出异常16四. 安全特性174.1 确保密码学加密算法密钥强度174.2 避免使用过时的加密算法174.3 避免使用不安全的填充(Padding)模式174.4 避免使用弱初始化向量(Initialization Vector)174.5 不要依赖isSecure()方法来决定是否传递敏感信息184.6 在敏感信息不再需要时显式清除它18- I -一. 安全隐患1.1 ProcessBuilder注入允许攻击者执行代码与Runtime类相似,如果ProcessBuilder对象根据不可信输入被构造,则有可能被攻击者用来进行命令注入攻击。错误的用法:public static void execUsingCommand(String command) throws Exception String args = new String cmd, /c, dir + command ;Process process = new ProcessBuilder().command(args).start();InputStream is = process.getInputStream();InputStreamReader isr = new InputStreamReader(is);BufferedReader br = new BufferedReader(isr);String line;while (line = br.readLine() != null) System.out.println(line); 在上述代码中,如果command参数来自不可信输入,如网页请求参数或请求URL,则代码存在命令注入漏洞。攻击者可以通过构造一个恶意输入,例如“/home/user & rm /app/config”,通过命令行同时执行多条命令。正确的做法是永远不要使用不可信输入构造ProcessBuilder对象,可以通过预定义可能的命令行列表,并根据用户输入来选择执行。1.2 确保public和static字段被定义为final如果一个public和static的字段,没有被定义为final,则不受信任的代码有可能通过修改此字段,影响对象的状态,造成潜在的攻击可能性。错误的用法:public class MyClass public static int counter = 123; /.正确的用法:public class MyClass public static final int counter = 123; /.1.3 包含敏感调用的方法应标记为final如果一个class没有被标记为final,那么他的所有方法都可以被重载(override)。如果它的一个方法调用了SecurityManager进行特权检查或其他敏感操作,例如AccessController.doPrivileged等,则应确保此方法被标记为final,否则可能被恶意使用者通过重载此方法,跳过预设的检测逻辑。错误的用法:public class BadSecurityCheck private int id;public BadSecurityCheck() securityCheck();id = 1;protected void doSecurityCheck() SecurityManager sm = System.getSecurityManager();if (sm != null) sm.checkPermission(new SomePermission(SomeAction);正确的用法:public final class GoodSecurityCheck private int id;public GoodSecurityCheck() doSecurityCheck();id = 1;protected final void doSecurityCheck() SecurityManager sm = System.getSecurityManager();if (sm != null) sm.checkPermission(new SomePermission(SomeAction);1.4 执行数据库查询前设置查询类型在执行数据库查询前,最好能设置查询类型为只读,来避免潜在的危险读写查询操作。例如在Castor/JDO中,通过设置只读查询,可以获得缺省共享查询几倍的响应速度,因为实现层不需要创建锁来避免其他线程的读写访问。正确的用法:query.execute(Database.ReadOnly);/jdo-best-practice.html在执行Hibernate查询前,可以设置LockMode属性为只读模式。正确的用法:query.setLockMode(alias, LockMode.READ)1.5 实现Serializable接口时没有定制序列化协议如果代码需要与不可信代码混杂使用,则需要确保包含敏感数据的对象,在实现了Serializable接口时,必须有相应的定制序列化协议。否则攻击者可以通过缺省的序列化协议实现,以java.io.ObjectOutputStream将对象序列化到外部存储,然后修改其中明文的敏感数据,再反序列化回来替换原始状态。为避免这类问题,应该实现自己的writeObject和readObject函数,提供特定逻辑对敏感数据进行保护,通过加密算法或哈希算法,避免可能的伪造和重放攻击。也可以通过将敏感字段,标记为transient来回避序列化操作。需要注意的是,序列化操作并不会受private修饰符的影响,所有非transient的字段都会参加序列化。正确的用法:import java.io.Serializable; public class MyClass implements Serializable private String sensitiveData; private void writeObject(ObjectOutputStream out) /generate hash this.secureFields(); out.defaultWriteObject(); private void readObject(ObjectInputStream in) this.load(); private secureFields() /encrypt(sensitiveData) fields here private load() in.defaultReadObject(); /check hash /decrypt fields and load into members /developer/technicalArticles/Programming/serialization/1.6 限制特权代码的可访问性对使用了特权代码调用的类和函数,应尽可能的降低其可访问性,例如设置为private。可以通过将此类代码独立出来,避免潜在的不可信任代码调用,或显式检查调用时权限。错误的用法: public static void doPrivilegedOpenFile(final String filePath) final BadFileNamePrivilegedAction pa = new BadFileNamePrivilegedAction(filePath);FileInputStream fis = null;try try fis = (FileInputStream)AccessController.doPrivileged(pa);/* * Continue processing the FileInputStream */ finally /* * Close the stream (if it exists) */if (fis != null) fis.close(); catch(PrivilegedActionException caught) LogHandler.log(Level.SEVERE, An error occurred while processing a file., caught); catch(IOException caught) LogHandler.log(Level.SEVERE, An error occurred while processing a file., caught);例如对访问特权操作AccessController.doPrivileged方法的函数,尽可能不要设置为public static,而通过private降低可访问性。正确的用法:private static void doPrivilegedOpenFile(final String filePath) final BadFileNamePrivilegedAction pa = new BadFileNamePrivilegedAction(filePath);FileInputStream fis = null;try try fis = (FileInputStream)AccessController.doPrivileged(pa);/* * Continue processing the FileInputStream */ finally /* * Close the stream (if it exists) */if (fis != null) fis.close(); catch(PrivilegedActionException caught) LogHandler.log(Level.SEVERE, An error occurred while processing a file., caught); catch(IOException caught) LogHandler.log(Level.SEVERE, An error occurred while processing a file., caught);1.7 确保SecurityManager权限检查的完整性在构造函数中使用SecurityManager进行权限检查,可以通过调用Clone()方法复制对象,或者readObject()/readObjectNoData()方法反序列化跳过,应确保这些代码路径被覆盖到。错误的用法: public class BadSecurityCheck implements Cloneable private int id;public BadSecurityCheck() SecurityManager sm = System.getSecurityManager();if (sm != null) sm.checkPermission(new BadPermission(BadSecurityCheck);id = 1;正确的用法:public class GoodSecurityCheck implements Cloneable private int id;public GoodSecurityCheck() doSecurityCheck();id = 1;public Object clone() throws CloneNotSupportedException GoodSecurityCheck bsm = (GoodSecurityCheck)super.clone();doSecurityCheck();return null;public void readObject(ObjectInputStream in) throws ClassNotFoundException, IOException in.defaultReadObject();doSecurityCheck();public void readObjectNoData(ObjectInputStream in) throws ClassNotFoundException, IOException in.defaultReadObject();doSecurityCheck();private final void doSecurityCheck() SecurityManager sm = System.getSecurityManager();if (sm != null) sm.checkPermission(new GoodPermission(GoodSecurityCheck);1.8 避免在public方法中返回private内部数据在public方法中,如果直接返回数组等内部数据,会导致其private修饰符失效,恶意使用者可以通过此内容修改内部数据状态。错误的用法: public final class urlTool extends Applet public final static URL urls;.正确的用法:public final class urlTool extends Applet private final static URL urls;.1.9 避免危险的public static final数组声明通常来说,如果将一个数组字段声明为public, static和final,可能是存在设计上的隐患。因为对这种情况来说,只能确保这个数组被一次赋值且无法改变,但并不能确保数组的内容不会被修改。在大多数情况下,此类数组应该被声明为private避免访问。错误的用法: public final class urlTool extends Applet public final static URL urls;.二. 环境配置2.1 不要将多类URL映射到同一个Servlet不要将多类URL映射到同一个Servlet,避免潜在的配置和权限错误,可以通过Web Server的URL重写达到类似效果。错误的配置: ServletA /servletA/* ServletA /servletB/*正确的配置: ServletA /servletA/* ServletB /servletB/*2.2 不要在配置文件中存放敏感信息不要将用户名和密码等敏感信息,硬编码到tomcat-users.xml等配置文件中。可以考虑通过LDAP或数据库查询动态获取;如果一定要存放在文件中,应通过密码学算法进行加密或哈希,避免伪造和重放等攻击。错误的配置: 错误的配置: sa pass . 正确的配置: 2.3 确保Servlet有名字并正确配置J2EE中部署描述脚本web.xml是Web应用中,用来定义所有servlet及其映射的最重要的部分。每个servlet都应该有唯一的名字(servlet-name),以及相应的映射(servlet-mapping)。错误的配置:! 缺少 节点: - com.class.MyServlet 1 !空 节点: - com.class.MyServlet 1 !重复 节点: - MyServlet Servlet com.class.MyServlet 1 正确的配置: MyServlet com.class.MyServlet 1 action org.apache.struts.action.ActionServlet 2可以通过使用相应DTD或XML schema,来确保配置文件的格式准确性。正确的配置:2.4 限制字段最大长度避免DoS或注入攻击在Struts中创建Form时,可以通过限制字段最大长度,降低遭受DoS或注入攻击的可能性。正确的配置: maxlength 10 三. 代码质量3.1 谨慎使用Thread.yield()方法首先,Thread.yield()方法是与JVM虚拟机实现紧密相关的,不同JVM实现中不会对其行为的一致性提供保障。其次,Thread.yield()方法只是对JVM虚拟机提供一个建议,因此无法产生明确和可信任的结果。实际上,在很多JVM实现中,此函数只是一个简单的NOP空指令而已,不会产生预期的结果。在处理器密集的运算循环中,Thread.yield()方法常被用来提示JVM调度其他线程,但因为实现原因其效果无法得到保障。对这种情况,可以采用Thread.sleep()方法替代,以获取更可靠的效果。/javase/tutorial/essential/concurrency/3.2 使用notifyAll方法替代notify在使用notify方法时,无法知道或指定哪个线程被唤醒,在某些情况下这可能会导致等待不同情况上的线程进入死锁。可以通过notifyAll方法来确保所有等待中的线程被唤醒。正确的用法:public synchronized int get() while (available = false) try wait(); catch (InterruptedException e) /do something available = false; notifyAll(); / notifies Producer return contents;/javase/tutorial/essential/concurrency/3.3 避免使用Thread的stop方法在使用Thread.stop方法时,被停止线程锁定的所有monitor都会被自动解锁,这可能会导致这些monitor保护的数据一致性无法得到保障,并将这些损坏的对象暴露给其他线程。大多数使用Thread.stop方法的场景,可以通过修改某个变量状态,并在线程中周期性检查此变量状态的方式模拟。如果线程处于等待状态,可以使用Terrupt方法中断。/javase/1.4.2/docs/guide/misc/threadPrimitiveDeprecation.html3.4 重新抛出ThreadDeath异常在线程处理代码中,应捕获并重新抛出ThreadDeath异常,以确保线程能被正常终止。正确的用法:try /some code catch(ThreadDeath td) throw td;/javase/1.4.2/docs/api/java/lang/ThreadDeath.html3.5 确保锁在发生异常时被正确释放如果在try代码块中获取了一个锁,必须在finally块中对其进行释放,否则在抛出异常时,会造成等待此锁的其它线程永久等待。错误的用法:import java.util.concurrent.locks.ReentrantLock;public class MyClass private final ReentrantLock mylock = new ReentrantLock(); public void foo() try myLock.lock(); performOperationInCriticalSection(); catch(IException e) myLock.unlock(); 在这种情况下,如果performOperationInCtiricalSection函数抛出异常,则锁将无法被正确释放,有可能造成死锁等问题。错误的用法:import java.util.concurrent.locks.ReentrantLock;public class MyClass private final ReentrantLock mylock = new ReentrantLock(); public void foo() try myLock.lock(); / . perform operations myLock.unlock(); catch(Exception e) /handle exception 在这种情况下,也无法确保unlock()调用被成功执行正确的用法:import java.util.concurrent.locks.ReentrantLockpublic class MyClass private final ReentrantLock mylock = new ReentrantLock(); public void foo() myLock.lock(); try / . perform operations catch(InterruptedException e) /handle exception finally myLock.unlock(); /javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.html3.6 避免在获取锁后调用sleep方法如果获取锁后调用sleep方法,可能导致系统响应速度变慢,或造成死锁。应尽可能通过设计来避免在等待前获取锁。3.7 避免在finally块中抛出异常在finally块中抛出异常,会破坏try-catch代码块的逻辑语义。Finally块是被设计用来进行清理工作的,代码逻辑应与try-catch中相匹配。错误的用法:public class MyClass public void doStuff() try /some code to try catch(FileNotFoundException ioe) /handle exception, and clean-up. finally throw new FileNotFoundException(); /pub/a/onjava/2003/11/19/exceptions.html四. 安全特性4.1 确保密码学加密算法密钥强度例如在NIST 标准 SP800-57规范中,推荐AES加密密钥至少128bit长,以确保数据在获得2030年计算能力之前的完整性和机密性。而RSA算法密钥则应确保在1024bit以上。降低密钥强度会减少数据被此加密方法保护的有效期,应针对常用的加密算法设定合适的最低密钥强度要求。正确的用法:KeyGenerator k = KeyGenerator.getInstance(AES);k.init(128);SecretKey key1 = k.generateKey();/publications/nistpubs/800-57/sp800-57-Part1-revised2_Mar08-2007.pdf4.2 避免使用过时的加密算法过时的加密算法,如DES和RC2存在被暴力猜解攻击的可能性。RC2在密钥强度过低的情况下也存在问题,例如密钥低于40bit。使用3DES或AES算法,配合高强度密钥来加密数据。http:/csr

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论