关于使用 HTML5、CSS3 和 JavaScript 开发 Web 应用,我们经常被问到的一个问题是如何隐藏代码。原因包括防止作弊、保护知识产权、隐藏加密算法等等。由于 JavaScript 是在客户端执行的,即使在 Firefox OS 上,用户也可以在拥有必要技能并花时间的情况下访问代码。但不要误解!Android、iOS 和大多数移动平台上的应用都可以通过努力和合适的工具进行反向工程。
我们将介绍一些措施,使模仿者更难揭示您的应用代码。在不同的程度上,这些措施将提高获取代码所需的努力、技能和工具。
压缩您的代码
这是大多数开发人员的起点。压缩您的代码通过删除浏览器运行您的应用不需要的内容来减小文件大小。它首先从剥离注释和不必要的空白开始。这是一个很好的第一步,因为注释通常会揭示大量关于代码如何工作的信息。
下一级是缩短局部变量和函数的名称,即所谓的混淆。由于这消除了这些符号的意义,因此它进一步降低了可读性。
更高级的压缩工具,如 UglifyJS,将实际解析您的 JavaScript 以分析和转换它。这不仅允许重命名局部符号,还允许将条件和循环重写为更短的表达式,合并变量声明(提升)并删除无法访问的代码。最终文件不仅更小,更难读,而且在许多情况下也更快。
您可以使用 Google Closure 优化器的高级模式将此进一步提高一个层次。该工具允许为所有上述转换设置。高级模式是最激进的,在使用时需要 仔细考虑,以确保输出与输入一样运行。它将重命名、内联甚至删除函数、属性和变量,因此您需要确保正确引用所有符号或对其进行注释。额外的努力会有所回报,因为结果是高度压缩的,甚至可以提高性能。例如,让我们看看这段代码会发生什么
document.onload = function() {
var shareImage = document.querySelector("#share-image");
function share() {
var imgToShare = document.querySelector("#image-to-share");
if (!imgToShare.naturalWidth) {
alert("Image failed to load, can't be shared");
return;
}
// Create dummy canvas
var blobCanvas = document.createElement("canvas");
blobCanvas.width = imgToShare.width;
blobCanvas.height = imgToShare.height;
// Get context and draw image
var blobCanvasContext = blobCanvas.getContext("2d");
blobCanvasContext.drawImage(imgToShare, 0, 0);
// Export to blob and share through a Web Activitiy
blobCanvas.toBlob(function (blob) {
var sharingImage = new MozActivity({
name: "share",
data: {
type: "image/*",
number: 1,
blobs: [blob]
}
});
});
};
shareImage.onclick = share;
};
一旦我们将这段代码运行到 Google Closure 中,代码将看起来像
var b=document.querySelector("#share-image"),
c=document.querySelector("#image-to-share");b&&c&&
(b.onclick=function(){if(0
Of course, the further you are writing custom logic, the more the code will be obfuscated, as the tools cannot change names from reserved word, or core functions. There are many tools online, and you can choose the one that fit your need. Most web frameworks offer interchangeable libraries and build steps that bundle and compress your JavaScript sources. For smaller projects your IDE, like Sublime Text, can be extended with packages available.
Using Emscripten
Did you remember that we said JavaScript is interpreted code? Well, you can bend that rule. Mozilla's Emscripten tool compiles C and C++ to JavaScript. The output isn't JavaScript as you know it. It behaves more like native code and manages its own memory (stack and heap) in pre-allocated typed arrays. This reduces garbage collection and makes inspecting the memory harder. The output also benefits from asm.js, a highly optimizable subset of JS, that runs on all modern browsers. If you are moving your app from native to the web you can just convert your existing libraries. But even if that doesn't apply, moving your protected code into a C/C++ library that you compile to JavaScript is the best option to get blazing performance with the added benefits of obfuscation.
Using a web service
Compression and compilation isn't the safest solution as people still have access to your code: it's just a bit harder to understand the logic. On the other side, one technique that moves the code to a place you have more control over is to use a web service. Your secret logic would run as a server-side script that your application will call when needed. Someone might be able to inspect the in- and outgoing data but there is no way they will be able to view your logic without access to your server. The major downside is that this feature will be only available when the user is online.
Let's see a simple example on how you can achieve this with a Firefox OS app, and a Node.js script: let's say we would like to hide our super exceptional fantastic code to do the addition to two numbers. Here is a simple node.js script (the goal is not to teach node.js, but show you a working basic example):
"use strict";
var express = require('express');
var app = express();
// Set up express to parse body
app.use(express.json());
app.use(express.urlencoded());
app.use(express.multipart());
// Only one route for web service
app.post('/', function(req, res) {
// Convert parameters from request body
var firstNumber = parseInt(req.body.firstNumber, 10);
var secondNumber = parseInt(req.body.secondNumber, 10);
if (isNaN(firstNumber) || isNaN(secondNumber)) {
// Bad request, fail with 400 status
return req.send(400);
}
var result = firstNumber + secondNumber;
res.send({'result': result});
});
app.listen(8000);
Now in your app, you'll call this script by sending the values you want to add, and the script will return you the result. Of course, users can see the call you make, and the results you'll get, but they won't be able to see the magic behind the hidden function.
"use strict";
var firstNumber = 4;
var secondNumber = 5;
var data = new FormData();
data.append("firstNumber", firstNumber);
data.append("secondNumber", secondNumber);
var xhr = new XMLHttpRequest({mozSystem: true});
xhr.open("POST", "http://fharper-nodejs.nodejitsu.com", true);
xhr.onload = function() {
// Parse the response and do something with it
var response = JSON.parse(xhr.response);
console.log(response.result);
};
xhr.onerror = function() {
console.log("Magic failed");
};
xhr.send(data);
This code is just showing the web service pattern and not best practices. As any server, it still needs security measures to prevent exploits. Make sure you mask the request and response data by using a secure HTTPS connection. Control client access to your service by checking the Referrer and Origin HTTP headers but don't trust what you see as they can be faked. You can limit replaying request with malicious parameters by using adding a secret time-limited or single-use token. As you can see, having your code in a web service is keeping it off the client but opens different attack vectors you need to consider.
Be proactive, open your code
Of course, the best approach is to open your code: make your application open source, choose the right license, and show to the rest of the world that you were the first to create this piece of art. Choose the technology you want: you will make it harder to copy your code, but there is never a way to hide your idea. You need to be proactive: you need to be one of the best in your domain. Show your expertise, innovate, add features faster than the competitor do, be relevant for your market, and believe in what you do. How many knock offs of Angry Birds can you find on the web or on any marketplace/store? I don't have the exact number, but I can definitely say with a lot of confidence, that it's many! Rovio had an amazing idea, and they were the first to make it a reality: they are always innovating with brand new levels, new games with the characters we like, and more. You, your children, myself, we want to play to the original one, not the copy. Replace Angry Birds with any app or games you like, and you'll understand what I mean.
You have access to an amazing platform that open the web like never before: take advantage of it, build that app you want, and make your idea a reality!
About
Harald Kirschner (digitarald)
Harald "digitarald" Kirschner is a Product Manager for Firefox's Developer Experience and Tools – striving to empower creators to code, design & maintain a web that is open and accessible to all. During his 8 years at Mozilla, he has grown his skill set amidst performance, web APIs, mobile, installable web apps, data visualization, and developer outreach projects.
More articles by Harald Kirschner (digitarald)…
About
Frédéric Harper
As a Senior Technical Evangelist at Mozilla, Fred shares his passion about the Open Web, and help developers be successful with Firefox OS. Experienced speaker, t-shirts wearer, long-time blogger, passionate hugger, and HTML5 lover, Fred lives in Montréal, and speak Frenglish. Always conscious about the importance of unicorns, and gnomes, you can read about these topics, and other thoughts at outofcomfortzone.net.
22 条评论