不知道你是用什么原理编译的,服务器系统是什么.
直接用java自带的类编译,这个我用过,好像得不到有效的错误的信息.也可能是本人水平问题.
直接使用java的Runtime调用系统的命令行来执行,这样是可以得到返回值的,但如果要高并发要好好研究下,这个东西很占资源,建议完全独立.并且通用性不高,因为windows和linux的命令是不同的,部署不同的服务器要写不同的命令.
另外这个系统不建议做成公开的,原因很简单,如果什么都能编译直接,我可以很简单的写代码来或者系统权限,放置后门程序,比如我可以写一个代码获取你JSP的所在文件目录,然后通过IO流写一个后门JSP,把流输出成文件放到那个位置,然后你的服务器就被攻占了.
对付高严重性暴露的技巧
请遵循下列建议以避免高严重性静态安全性暴露:
限制对变量的访问
让每个类和方法都成为 final,除非有足够的理由不这样做
不要依赖包作用域
使类不可克隆
使类不可序列化
使类不可逆序列化
避免硬编码敏感数据
查找恶意代码
如果将变量声明为 public,那么外部代码就可以操作该变量.这可能会导致安全性暴露.
影响
如果实例变量为 public,那么就可以在类实例上直接访问和操作该实例变量.将实例变量声明为 protected 并不一定能解决这一问题:虽然不可能直接在类实例基础上访问这样的变量,但仍然可以从派生类访问这个变量.
清单 1 演示了带有 public 变量的代码,因为变量为 public 的,所以它暴露了.
清单 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; // this should not be allowed
public static void main(String[] args){
Test obj = new Test();
MyClass mc = new MyClass();
mc.methodIllegalSet("Illegal Set Value");
建议
private int id;
private String name;
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;
让每个类和方法都为 final
不允许扩展的类和方法应该声明为 final.这样做防止了系统外的代码扩展类并修改类的行为.
仅仅将类声明为非 public 并不能防止攻击者扩展类,因为仍然可以从它自己的包内访问该类.
让每个类和方法都成为 final,除非有足够的理由不这样做.按此建议,我们要求您放弃可扩展性,虽然它是使用诸如 Java 语言之类的面向对象语言的主要优点之一.在试图提供安全性时,可扩展性却成了您的敌人;可扩展性只会为攻击者提供更多给您带来麻烦的方法.
没有显式地标注为 public、private 或 protected 的类、方法和变量在它们自己的包内是可访问的.
如果 Java 包不是封闭的,那么攻击者就可以向包内引入新类并使用该新类来访问您想保护的内容.诸如 java.lang 之类的一些包缺省是封闭的,一些 JVM 也让您封闭自己的包.然而,您最好假定包是不封闭的.
从软件工程观点来看,包作用域具有重要意义,因为它可以阻止对您想隐藏的内容进行偶然的、无意中的访问.但不要依靠它来获取安全性.应该将类、方法和变量显式标注为 public、private 或 protected 中适合您特定需求的那种.
克隆允许绕过构造器而轻易地复制类实例.
class MyClass{
public MyClass(){
id=1;
name="HaryPorter";
public MyClass(int id,String name){
this.id=id;
this.name=name;
System.out.println("Id ="+id+"
"+"Name="+name);
// hackers code to clone the user class
public class Hacker extends MyClass implements Cloneable {
Hacker hack=new Hacker();
try{
MyClass o=(MyClass)hack.clone();
catch(CloneNotSupportedException e){
e.printStackTrace();
public final Object clone()
throws java.lang.CloneNotSupportedException{
throw new java.lang.CloneNotSupportedException();
throws java.lang.CloneNotSupportedException {
super.clone();
类中出现 clone() 方法防止攻击者重新定义您的 clone 方法.
序列化允许将类实例中的数据保存在外部文件中.闯入代码可以克隆或复制实例,然后对它进行序列化.
序列化是令人担忧的,因为它允许外部源获取对您的对象的内部状态的控制.这一外部源可以将您的对象之一序列化成攻击者随后可以读取的字节数组,这使得攻击者可以完全审查您的对象的内部状态,包括您标记为 private 的任何字段.它也允许攻击者访问您引用的任何对象的内部状态.
private final void writeObject(ObjectOutputStream out)
throws java.io.NotSerializableException {
throw new java.io.NotSerializableException("This object cannot
be serialized");
通过将 writeObject() 方法声明为 final,防止了攻击者覆盖该方法.
通过使用逆序列化,攻击者可以用外部数据或字节流来实例化类.
不管类是否可以序列化,都可以对它进行逆序列化.外部源可以创建逆序列化成类实例的字节序列.这种可能为您带来了大量风险,因为您不能控制逆序列化对象的状态.请将逆序列化作为您的对象的另一种公共构造器 — 一种您无法控制的构造器.
private final void readObject(ObjectInputStream in)
be deserialized");
通过将该方法声明为 final,防止了攻击者覆盖该方法.
您可能会尝试将诸如加密密钥之类的秘密存放在您的应用程序或库的代码.对于你们开发人员来说,这样做通常会把事情变得更简单.
任何运行您的代码的人都可以完全访问以这种方法存储的秘密.没有什么东西可以防止心怀叵测的程序员或虚拟机窥探您的代码并了解其秘密.
可以以一种只可被您解密的方式将秘密存储在您代码中.在这种情形下,秘密只在于您的代码所使用的算法.这样做没有多大坏处,但不要洋洋得意,认为这样做提供了牢固的保护.您可以遮掩您的源代码或字节码 — 也就是,以一种为了解密必须知道加密格式的方法对源代码或字节码进行加密 — 但攻击者极有可能能够推断出加密格式,对遮掩的代码进行逆向工程从而揭露其秘密.
这一问题的一种可能解决方案是:将敏感数据保存在属性文件中,无论什么时候需要这些数据,都可以从该文件读取.如果数据极其敏感,那么在访问属性文件时,您的应用程序应该使用一些加密/解密技术.
从事某个项目的某个心怀叵测的开发人员可能故意引入易受攻击的代码,打算日后利用它.这样的代码在初始化时可能会启动一个后台进程,该进程可以为闯入者开后门.它也可以更改一些敏感数据.
这样的恶意代码有三类:
类中的 main 方法
定义过且未使用的方法
注释中的死代码
入口点程序可能很危险而且有恶意.通常,Java 开发人员往往在其类中编写 main() 方法,这有助于测试单个类的功能.当类从测试转移到生产环境时,带有 main() 方法的类就成为了对应用程序的潜在威胁,因为闯入者将它们用作入口点.
请检查代码中是否有未使用的方法出现.这些方法在测试期间将会通过所有的安全检查,因为在代码中不调用它们 — 但它们可能含有硬编码在它们内部的敏感数据(虽然是测试数据).引入一小段代码的攻击者随后可能调用这样的方法.
避免最终应用程序中的死代码(注释内的代码).如果闯入者去掉了对这样的代码的注释,那么代码可能会影响系统的功能性.
public void unusedMethod(){
// code written to harm the system
public void usedMethod(){
//unusedMethod(); //code in comment put with bad intentions,
//might affect the system if uncommented
// int x = 100;
// x=x+10; //Code in comment, might affect the
//functionality of the system if uncommented
应该将(除启动应用程序的 main() 方法之外的)main() 方法、未使用的方法以及死代码从应用程序代码中除去.在软件交付使用之前,主要开发人员应该对敏感应用程序进行一次全面的代码评审.应该使用"Stub"或"dummy"类代替 main() 方法以测试应用程序的功能.
对付中等严重性暴露的技巧
请遵循下列建议以避免中等严重性静态安全性暴露:
不要依赖初始化
不要通过名称来比较类
不要使用内部类
您可以不运行构造器而分配对象.这些对象使用起来不安全,因为它们不是通过构造器初始化的.
在初始化时验证对象确保了数据的完整性.
例如,请想象为客户创建新帐户的 Account 对象.只有在 Account 期初余额大于 0 时,才可以开设新帐户.可以在构造器里执行这样的验证.有些人未执行构造器而创建 Account 对象,他可能创建了一个具有一些负值的新帐户,这样会使系统不一致,容易受到进一步的干预.
public class MyClass{
private boolean initialized = false;
//Other variables
public MyClass (){
//variable initialization
method1();
initialized = true;
private void method1(){ //no need to check for initialization variable
if(initialized==true){
//proceed with the business logic
else{
throw new Exception("Illegal State Of the object");
}catch(Exception e){
如果对象由逆序列化进行初始化,那么上面讨论的验证机制将难以奏效,因为在该过程中并不调用构造器.在这种情况下,类应该实现 ObjectInputValidation 接口:
清单 10. 实现 ObjectInputValidation
interface java.io.ObjectInputValidation {
public void validateObject() throws InvalidObjectException;
所有验证都应该在 validateObject() 方法中执行.对象还必须调用 ObjectInputStream.RegisterValidation() 方法以为逆序列化对象之后的验证进行注册. RegisterValidation() 的第一个参数是实现 validateObject() 的对象,通常是对对象自身的引用.注:任何实现 validateObject() 的对象都可能充当对象验证器,但对象通常验证它自己对其它对象的引用.RegisterValidation() 的第二个参数是一个确定回调顺序的整数优先级,优先级数字大的比优先级数字小的先回调.同一优先级内的回调顺序则不确定.
当对象已逆序列化时,ObjectInputStream 按照从高到低的优先级顺序调用每个已注册对象上的 validateObject().
有时候,您可能需要比较两个对象的类,以确定它们是否相同;或者,您可能想看看某个对象是否是某个特定类的实例.因为 JVM 可能包括多个具有相同名称的类(具有相同名称但却在不同包内的类),所以您不应该根据名称来比较类.
如果根据名称来比较类,您可能无意中将您不希望授予别人的权利授予了闯入者的类,因为闯入者可以定义与您的类同名的类.
例如,请假设您想确定某个对象是否是类 com.bar.Foo 的实例.清单 11 演示了完成这一任务的错误方法:
清单 11. 比较类的错误方法
if(obj.getClass().getName().equals("Foo")) // Wrong!
// objects class is named Foo
}else{
// object's class has some other name
if(obj.getClass() == this.getClassLoader().loadClass("com.bar.Foo")){
// object's class is equal to
//the class that this class calls "com.bar.Foo"
// object's class is not equal to the class that
// this class calls "com.bar.Foo"
if(a.getClass() == b.getClass()){
// objects have the same class
// objects have different classes
尽可能少用直接名称比较.
Java 字节码没有内部类的概念,因为编译器将内部类转换成了普通类,而如果没有将内部类声明为 private,则同一个包内的任何代码恰好能访问该普通类.
因为有这一特性,所以包内的恶意代码可以访问这些内部类.如果内部类能够访问括起外部类的字段,那么情况会变得更糟.可能已经将这些字段声明为 private,这样内部类就被转换成了独立类,但当内部类访问外部类的字段时,编译器就将这些字段从专用(private)的变为在包(package)的作用域内有效的.内部类暴露了已经够糟糕的了,但更糟糕的是编译器使您将某些字段成为 private 的举动成为徒劳.
建议 如果能够不使用内部类就不要使用内部类.
对付低严重性暴露的技巧
请遵循下列建议以避免低严重性静态安全性暴露:
避免返回可变对象
检查本机方法
Java 方法返回对象引用的副本.如果实际对象是可改变的,那么使用这样一个引用调用程序可能会改变它的内容,通常这是我们所不希望见到的.
请考虑这个示例:某个方法返回一个对敏感对象的内部数组的引用,假定该方法的调用程序不改变这些对象.即使数组对象本身是不可改变的,也可以在数组对象以外操作数组的内容,这种操作将反映在返回该数组的对象中.如果该方法返回可改变的对象,那么事情会变得更糟;外部实体可以改变在那个类中声明的 public 变量,这种改变将反映在实际对象中.
class Exposed{
public Exposed(){
public Exposed(int id, String name){
System.out.println("Id = "+ id + " Name = "+ name);
private Exposed exposedObj = new Exposed(1,"Harry Porter");
public Exposed getExposedObj(){
return exposedObj; //returns a reference to the object.
exposed.setId(10);
exposed.setName("Hacker");
return new Exposed(exposedObj.getId(),exposedObj.getName());
或者,您的代码也可以返回 Exposed 对象的克隆.
本机方法是一种 Java 方法,其实现是用另一种编程语言编写的,如 C 或 C++.有些开发人员实现本机方法,这是因为 Java 语言即使使用即时(just-in-time)编译器也比许多编译过的语言要慢.其它人需要使用本机代码是为了在 JVM 以外实现特定于平台的功能.
使用本机代码时,请小心,因为对这些代码进行验证是不可能的,而且本机代码可能潜在地允许 applet 绕过通常的安全性管理器(Security Manager)和 Java 对设备访问的控制.
如果非得使用本机方法,那么请检查这些方法以确定:
它们返回什么
它们获取什么作为参数
它们是否绕过安全性检查
它们是否是 public、private 等等
它们是否含有绕过包边界从而绕过包保护的方法调用
结束语
编写安全 Java 代码是十分困难的,但本文描述了一些可行的实践来帮您编写安全 Java 代码.这些建议并不能解决您的所有安全性问题,但它们将减少暴露数目.最佳软件安全性实践可以帮助确保软件正常运行.安全至关重要和高可靠系统设计者总是花费大量精力来分析和跟踪软件行为.只有通过将安全性作为至关紧要的系统特性来对待 — 并且从一开始就将它构建到应用程序中,我们才可以避免亡羊补牢似的、修修补补的安全性方法.
参考资料
请通过单击文章顶部或底部的讨论来参加本文的论坛.
了解关于 Java 安全性 API 的更多知识.
developerWorks 安全专题上通常含有有关计算机安全性的优秀资源.
第一部分
第二部分
定期检查 IBM 研究 Java 安全页面以便 IBM 在安全性领域的创新有重要发展时能够跟踪这一创新.
java在Windows下会有限制..
一般的系统中没装JVM,所以,病毒根本没办法运行..
另外,希望不要被JBuilder误导,它所生成的.exe程序其实只是一个壳子,双击运行的时候,它其实背地里启动了JVM...
所以,JB生成的.exe程序也需要有JVM Java虚拟机 为前提条件..
建议 采用 c语言 汇编 C++ ,VB还得要个VB运行库,呵呵,和那JB差不多都有缺性
以上就是土嘎嘎小编为大家整理的在java代码中写后门相关主题介绍,如果您觉得小编更新的文章只要能对粉丝们有用,就是我们最大的鼓励和动力,不要忘记讲本站分享给您身边的朋友哦!!