者:京东零售 周明亮
亚马逊商详地址:
https://www.amazon.com/OtterBox-Commuter-Case-iPhone-Packaging
主要配合接口进行加密,采用多字段干扰,模板化加载。下发大量的模版数据,之后通过客户端进行填充。
客户端代码为传统的普通加密模式
这个只是部分代码,如果将完整代码,一段一段进行分析,你就可以得到完整上下文,不需要靠人去一段一段读取代码。
目前还有 ai 代码调试如:
https://github.com/shobrook/adrenaline?
1)自身不愿意登录,或者偷取正常用户信息后,用于攻击
2)如果是公司行为,很可能会被记录IP,有法务风险。
3)多次进行尝试修改 token ,伪装发送请求
4)分析 DOM 结构特征 / 使用 Console 打印全局存储变量
5)通过 cookies 分析特定的关键词,全局搜索
6)网络请求时,查看函数执行栈,逐级往下寻找核心请求函数。
1)前端代码采用传统加密方式
2)入口在 APP 内的 业务
3)对关键词进行混淆处理,减少特征搜索
任何客户端加密混淆都会被破解,只要用心都能解决,我们能做的就是拖延被破解的时间,而不是什么都不做,那样只会被破解更快!
其实很多我们自己公司对外的页面,都有很多外露风险,包括不规范的日志输出,直接对外暴露加密的防刷 token。 比如:
?大家都可以自查下~
今互联网时代,JavaScript已经成为了web前端开发的重点技术之一。其中,JavaScript代码的安全性问题一直是关注的焦点。为了保护JavaScript代码的安全性,很多人对其进行加密处理,众所周知,对于单纯的加密算法,通过反向工程或逆向分析也能够破解。在此情况下,JavaScript代码混淆技术成为了一种应对加密破解的有效措施。
一、JS加密算法
JS加密算法是指JavaScript代码通过异或加密、Base64加密、MD5加密、SHA1加密等方式对其内容进行加密处理。例如,下面的加密函数中,通过异或运算对字符串进行了加密:
Copy codefunction encryptByXOR(message, key) {
var encrypted='';
for (var i=0; i < message.length; i++) {
var c=message.charCodeAt(i) ^ key.charCodeAt(i % key.length);
encrypted +=String.fromCharCode(c);
}
return encrypted;
}
var message='Hello world';
var key='1234567890';
var encrypted_message=encryptByXOR(message, key);
console.log('加密后的字符串:', encrypted_message);
通过对源代码进行加密处理,能够为JavaScript代码的安全性提供一定的保障。不过,对于相同的JavaScript加密算法,破解者也可以使用同样的加解密算法进行反向操作。而且,使用加密算法会增加代码的体积,降低代码的执行速度。因此,人们开始思考是否有一种更好的方法确保JavaScript代码的安全性呢?
二、JS代码混淆技术
JS代码混淆技术可以将JavaScript代码转换成一个新的代码形式,使其难以理解和破解。这种转换通常包括将变量名和函数名替换为无意义的字符、删除代码中的空白和注释、将多行代码压缩成一行等操作。混淆后的代码和原代码在功能上是等效的,但是由于其结构和命名被混淆,甚至看起来无法读懂。
例如,下面的函数中,对一段JavaScript代码进行了简单的混淆处理:
Copy codefunction obfuscateCode(code) {
var lines=code.split("\n");
var obfuscatedCode="";
lines.forEach(function(line) {
obfuscatedCode +=line
.replace(/var /g, "")
.replace(/function /g, "")
.replace(/return /g, "")
.replace(/;/g, "")
.replace(/{/g, "")
.replace(/}/g, "");
});
return obfuscatedCode;
}
var original_code='function foo(a, b) {var c=a + b;return c;}';
var obfuscated_code=obfuscateCode(original_code);
console.log('原始代码:', original_code);
console.log('混淆代码:', obfuscated_code);
通过混淆技术,原始JavaScript代码变得更加复杂和难以理解,进而降低了破解的可行性。同时,相比与加密算法,混淆代码的运行速度和性能也更优秀。
三、JS解混淆技术
不过,对于代码混淆技术,我们同样可以将其污染(反混淆)。通过分析混淆代码的结构和操作,我们能够撰写出解混淆代码,进行JavaScript代码的还原。例如,混淆代码可能会将许多不同的变量名替换为相同的单个字符,或者将多个行的代码压缩到一个代码行中,可以通过自动化工具或手动方法来反混淆代码。
Copy codefunction unobfuscateCode(obfuscatedCode) {
var unobfuscatedCode=obfuscatedCode
.replace(/a /g, "var ")
.replace(/b /g, "function ")
.replace(/c /g, "return ")
.replace(/[0-9]+/g, "")
.replace(/=/g, "=")
.replace(/\+/g, " + ")
.replace(/;/g, ";\n")
.replace(/}/g, "\n}\n")
.replace(/^\n/, "");
return unobfuscatedCode;
}
var obfuscated_code="b foo(a, b){c a + b}"; //从js.jiami.com上获得的混淆代码
var unobfuscated_code=unobfuscateCode(obfuscated_code);
console.log('混淆代码:', obfuscated_code);
console.log('原始代码:', unobfuscated_code);
四、JS代码安全实践
如何选择适当的JS代码安全实践方法,取决于应用程序所需的安全级别和安全需求。如果您需要保护代码内容的安全,可以使用加密算法。如果您的代码需要长期维护,可以使用代码混淆技术,使代码的可读性降低,这样也就不容易被别人拿来二次开发和篡改。如果您需要将代码保持可读性,但是又需要保护代码的安全性,可以采取混合应用加密算法和混淆技术相互结合,以最佳的方式实现代码保护。
总之,随着互联网技术的发展,对于网络安全的要求越来越高,对于JavaScript的加密和解密,技术发展均取得了一定的进步。但无论是黑客攻击还是加密解密技术,只是给我们提供了预防的参考方案,绝不能代替不断加强网站的安全性实践,并高度唤起安全保护意识。
jsjiami.com
如果您对文章内容有不同看法,或者疑问,欢迎到评论区留言,或者私信我都可以。
也可以到上方网站,底部有我联系方式详谈。
java的bytecode很容易通过JAD等反编译工具还原出源代码。这样势必不满足安全的定义。如何一定程度上保护需要防止被反编译的源代码呢?混淆(obfuscate)技术。注意:用obfuscate防盗版是根本不可能,连汇编这种东西都能被**掉,而java代码基本上等同于开源的同义词。用obfuscate只是为了增加反编译的难度,保护源代码的知识产权。混淆包照常运行,没有任何问题。可以使用反编译工具如jd-gui查看混淆后的包,验证混淆效果。
将有意义的类,字段、方法名称更改为无意义的字符串。生成的新名称越 短,字节代码越小。在名称混淆的字节代码中,包,类,字段和方法名称已重命名,并且永远不能恢复原始名称。
用于if, switch, while,for等关键字,对字节码进行细微的修改,模糊控制流,而不改变代码在运行时的行为。通常情况下,选择和循环等逻辑构造会被更改,因此它们不再具有直接等效的Java源代码。流模糊的字节码通常强制反编译器将一系列标签和非法的goto语句插入到它们生成的源代码中。源代码有时会因为反编译错误而变得更加模糊。
proguard是一个免费的 Java类文件的压缩,优化,混肴器。它删除没有用的类,字段,方法与属性。使字节码最大程度地优化,使用简短且无意义的名字来重命名类、字段和方法
官网地址:https://www.guardsquare.com/en/products/proguard
yGuard是一款免费的Java混淆器(非开源),它有Java和.NET两个版本。yGuard 完全免费,基于 Ant 任务运行,提供高可配置的混淆规则。
官网地址:https://www.yworks.com/products/yguard
第二代Java混淆器。所谓第二代混淆器,不仅仅能进行字段混淆,还能实现流混淆。
命名混淆,流混淆,调试信息混淆,字符串编码,以及水印技术。对于教育和非商业项目来说这个混淆器是免费的。支持war和jar格式,支持对需要混淆代码的应用程序添加有效日期。
官网地址:http://www.allatori.com/
推荐使用 proguard :开源, 使用简单 ,文档丰富完善。
工具 | 官网地址 | 官方文档 | 开源免费 | 名称混淆 | 流混淆 | maven支持 | 功能 |
proguard | https://www.guardsquare.com/proguard | https://www.guardsquare.com/manual/home | √ | √ | ? | √ | |
yGuard | https://www.yworks.com/products/yguard | https://yworks.github.io/yGuard/ | √ | √ | ? | √ | |
allatori | https://allatori.com/ | ?(免费用于教育和非商业项目) | √ | √ | √ | 减小包大小;混淆代码;添加水印 |
是一个开源的 Java 类文件收缩器、优化器、混淆器和预验证器。因此,ProGuard 处理的应用程序和库更小、更快,并且在一定程度上可以抵御逆向工程。
<build>
<plugins>
<plugin>
<!--结合ant run 来使用yguard -->
<artifactId>maven-antrun-plugin</artifactId>
<dependencies>
<dependency>
<groupId>com.yworks</groupId>
<artifactId>yguard</artifactId>
<version>3.1.0</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<property refid="maven.compile.classpath" name="mvn.classpath"/>
<!-- <echo message="Using Maven Classpath: ${mvn.classpath}" /> -->
<taskdef name="yguard"
classname="com.yworks.yguard.YGuardTask"/>
<yguard>
<!-- yguard配置 -->
</yguard>
</tasks>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<!-- yguard 是公用配置和rename以及shrink配置的容器标签 -->
<yguard>
<!-- 必须至少指定一个inoutpair元素或一个非空inoutpairs元素才能运行yguard任务。此元素指定输入和输出 jar 文件的路径
in out 必须指定设置值,不指定报错
1.in 指定一个现有的jar/war文件,其中包含未收缩和未混淆的 .class文件。
2.out 指定一个 jar/war文件的路径,该文件将被创建并用于放置收缩和混淆过程的结果。
3.resources 如何处理资源文件,支持三种值:copy,auto,none。 默认配置copy。
1.copy 直接复制资源文件 默认情况下,只需将所有资源文件复制到输出 jar 中
2.auto 仅复制那些在压缩后仍包含一个或多个 .class 文件的目录中的资源文件。
3.none 丢弃所有资源文件。-->
<inoutpair
in="${project.build.directory}/${project.build.finalName}.${project.packaging}"
out="${project.build.directory}/${project.build.finalName}.${project.packaging}" />
<externalclasses>
</externalclasses>
<!-- 用于配置一些属性 ,保存类的调试信息:比如 LineNumberTable:行号表;LocalVariableTable:本地变量表等。 -->
<attribute name="SourceFile, LineNumberTable, LocalVariableTable">
<patternset>
<include name="com.ewa.pipe.**"/>
</patternset>
</attribute>
<!-- shrink 用于收缩代码配置。
1.logfile shrink过程的日志文件
2.在shrink过程中,如果有错误代码,代码将会被替换为: throw new InternalError("Badly shrinked")。
比如:当某些类的private属性被删除,但是public方法中有引用该属性,而属性被删除了,即会输出该异常错误。
-->
<shrink logfile="${project.build.directory}/yshrink.log.xml" createStubs="true">
<!-- shrink中的keep和rename中的keep一致。 -->
<keep>
<method name="void main(java.lang.String[])" class="${mainclass}" />
</keep>
</shrink>
<!-- 用于自定义某些配置和属性更改。
1.mainclass 用于设置主程序启动位置,该文件将不会被混淆。
2.logfile 混淆过程中的日志文件保存地址。名称以“.gz”结尾,yGuard 将自动创建文件的 gzip 压缩版本,默认为yguardlog.xml
3.conservemanifest 当为false时,重新生成 MANIFEST.MF的内容。默认为false。
4.replaceClassNameStrings 是否混淆代码中某些字符串跟类名相关的东西。默认为true
比如源码: System.out.print("com.ewa.pipe.dbtransfer.dpl.mapper.BlendMapper");混淆后: System.out.print("com.ewa.pipe.dbtransfer.dpl.A.B");
5.scramble 是否随机混淆代码,默认false。如果为true即每次打包生成的类名将随机替换。比如Test.class 第一次混淆为A.class,第二次就为B.class
6.annotationClass 某些不必要混淆的数据,比如如下配置为Test注解,当配置到类上时,类中的所有东西不会被混淆;当配置到属性时,属性名称不会被混淆。
-->
<rename
mainclass="com.ewa.pipe.dbtransfer.dpl.DplDbtransferApplication"
logfile="${project.build.directory}/yguard.log.xml"
conservemanifest="false"
replaceClassNameStrings="true"
scramble="false"
annotationClass="com.ewa.pipe.dbtransfer.dpl.Test"
>
<!-- -->
<keep>
</keep>
<!-- 1.error-checking 用于检测错误,检测到错误就失败停止。 -->
<property name="error-checking" value="pedantic"/>
<!-- 2.error-checking 可用于告诉重命名引擎在混淆期间使用不同的命名方案。目前可以将此属性设置为以下值之一(默认small,通常使用small就行了):
small:将产生非常短的名称,即生成的 jar 文件将尽可能小。
best:会产生很可能被反编译器和反汇编器误解的名称。使用这种命名方案,在大多数文件系统上甚至不可能成功解压缩或解压缩生成的 jar 文件(Windows、Standard Unix、Standard Linux、MacOS)。然而,这种方案占用了大量空间,并且生成的 jar 可能会变大(通常大约是两倍大小)。
mix:是其他两个值的混合,这会导致合理的小但仍然难以反编译 jar 文件。
-->
<!-- 其他属性( language-conformity ,overload-enabled,obfuscation-prefix,digests,expose-attributes)请参考官方文档。 -->
<property name="naming-scheme" value="small"/>
</rename>
</yguard>
class用于在rename和shrink过程中排除某些类,字段和方法。其是keep的子元素。以下是配置说明(- 表示会被收缩,即被删除 ):
可见性(是否被收缩) | public | protected | friendly | private |
none | - | - | - | - |
public | * | - | - | - |
protected | * | * | - | - |
friendly | * | * | * | - |
private | * | * | * | * |
属性说明
注意事项
列1:
<shrink logfile="${project.build.directory}/yshrink.log.xml">
<keep>
<!-- 保留NameTest类不被删除,但是内部的方法和会属性会被删除,不论私有还是共有。 -->
<class name="com.arm.code.mix.base.NameTest"/>
<!-- 保留所有公用的类,方法和属性。其关联的类,方法和属性会被保留,不会被删除 -->
<class classes="public" methods="public" fields="public"/>
<!-- 保留所有继承了BaseClass的类不被删除,但是内部的方法和会属性会被删除,不论私有还是共有。 -->
<class extends="com.arm.code.mix.base.BaseClass"/>
</keep>
</shrink>
列2:
<shrink logfile="${project.build.directory}/yshrink.log.xml">
<keep>
<!-- 保留NameTest类不被删除,并保留其private级别的方法和属性 -->
<class name="com.arm.code.mix.base.NameTest" methods="private" fields="private"/>
<!-- 保留所有继承了BaseClass的类不被删除,并保留其private级别的方法和属性 -->
<class extends="com.arm.code.mix.base.BaseClass" methods="private" fields="private"/>
</keep>
</shrink>
列3:
一下举列几个模式集的列子,模式集可以参考ant。
<!-- include shrink:不需要被删除的类,保留的类。rename:不需要被混淆的类名 -->
<class>
<patternset>
<include name="com.mycompany.**.*Bean"/>
<exclude name="com.mycompany.secretpackage.*"/>
<exclude name="com.mycompany.myapp.SecretBean"/>
<!-- 由于 Ant'$'用作转义字符,因此如果您想将一个作为参数传递给任务,则必须使用两个连续的'$'s( )。'$$'-->
<exclude name="org.w3c.sax?.**.*$$*"/>
</patternset>
</class>
method 用于在rename和shrink过程中排除方法。其是keep的子元素。以下是配置说明(- 表示会被收缩,即被删除 ):
<!-- 这将保留MyClass类的main和foo方法。此外,所有readObject和writeObject方法(用于序列化)都将保存在com.mycompany.myapp.data包的所有类中。
请注意,您必须指定返回参数的类型,即使它是 void,并且您必须为所有类使用完全限定名称,即使是java.lang package. -->
<method class="com.mycompany.myapp.MyClass"
name="void main(java.lang.String[])"/>
<method class="com.mycompany.myapp.MyClass"
name="int foo(double[][], java.lang.Object)"/>
<method name="void writeObject(java.io.ObjectOutputStream)">
<patternset>
<include name="com.mycompany.myapp.data.*"/>
</patternset>
</method>
<method name="void readObject(java.io.ObjectInputStream)">
<patternset>
<include name="com.mycompany.myapp.data.*"/>
</patternset>
</method>
field 您可以按名称指定应从收缩或名称混淆中要保留的字段
<!-- 保留MyClass类中的所有字段。
此外,所有serialVersionUID字段(用于序列化)都将保存在com.mycompany.myapp.data包的所有类中。 -->
<field class="com.mycompany.myapp.MyClass" name="field"/>
<field name="serialVersionUID">
<patternset>
<include name="com.mycompany.myapp.data.*"/>
</patternset>
</field>
package 用于从重命名过程中排除某些包的名称。它不能用于收缩(shrink)过程 。这对类、方法或字段名称没有影响。
<package>
<patternset>
<!-- com.mycompany.myapp不被混淆。myapp下的包名还是会被混淆 -->
<include name="com.mycompany.myapp.*"/>
<!-- com.mycompany.myapp不被混淆。myapp下的包名也不会被混淆 -->
<include name="com.mycompany.myapp.**"/>
</patternset>
</package>
1.注意事项
2.项目使用失败的问题收集总结
3.配置模版
<keep>
<!--包名不混淆配置-->
<package>
<patternset>
<include name="com.arm.oceansearch.**"/>
</patternset>
</package>
<!--mybaites 相关的mapper混淆后,会造成boot项目启动失败 -->
<class implements="com.arm.boot.core.base.BaseMapper"/>
<!--mybaites默认生成sql时是使用的实体类的类名,所以不能混淆-->
<class implements="com.arm.oceansearch.entity.BaseEntity"/>
<!-- 本包的controller混淆后,无法读取mapping映射,原因未知。-->
<class>
<patternset>
<include name="com.arm.oceansearch.controller.*"/>
</patternset>
</class>
<!-- service的接口和实现都要暴露,不然spring的注入和nacos的服务发现都会存在问题。 -->
<class>
<patternset>
<include name="com.arm.oceansearch.service.**"/>
</patternset>
</class>
<!--main方法配置-->
<method name="void main(java.lang.String[])"
class="com.arm.oceansearch.OceanSearchApplication"/>
</keep>
ProGuard 是一个开源的 Java 类文件收缩器、优化器、混淆器和预验证器。因此,ProGuard 处理的应用程序和库更小、更快,并且在一定程度上可以抵御逆向工程。
反射和内省对于任何代码的自动处理都存在特殊的问题。在 ProGuard 中,代码中动态创建或调用(即按名称)的类或类成员也必须指定为入口点。例如,Class.forName()构造可以在运行时引用任何类。通常不可能计算必须保留哪些类(使用它们的原始名称),因为类名可能是从配置文件中读取的,例如。因此,您必须在 ProGuard 配置中指定它们,同样简单-keep选项
处理:<inFilter>com/ewa/pipe/**</inFilter>, inFilter标签设置为包路径地址,把‘.’换成‘/’。
injar : 指定target中的一个目标地址:这里指定编译后的 classes文件夹。 inFilter 指定的是 classes的内部的文件夹(package)地址。
<!-- 加载文件的过滤器,就是你的工程目录了-->
<inFilter>com/arm/code/**</inFilter>
<!-- 对什么东西进行加载,这里仅有classes成功,毕竟你也不可能对配置文件及JSP混淆吧-->
<injar>classes</injar>
以下是一个例子说明,如果你想更多的有用信息,请查看文档(https://www.guardsquare.com/manual/configuration/usage)
*请认真填写需求信息,我们会在24小时内与您取得联系。