|
我们都知道HTML5应用都是开放源码的,也就是你的Web应用开发出来之后大家都是可以对其源码进行拷贝、改造的,至少到目前为止还没有什么通用的方法能够保护开发者的产权,尽管JS混淆或JS压缩在一定程度上给破解者带来的难度,但是并不能完全保证开发者的利益。正如前段时间火爆一时的2048游戏,自从其作者Gabriele Cirulli将其发布在github上之后,网上迅速出现了各种版本,并被移植到各种平台之上,某些甚至植入了各种广告;因此通过何种加密手段或其他手段来保护开发者的劳动成果和知识产权,甚至是保证数据的安全性也是在HTML5越来越火爆的大背景下需要解决的问题。
三星的Tizen系统从3.0开始使用Crosswalk作为其WebRuntime引擎,在分析其代码时看到了crosswalk对于Web应用的加密实现,下面就从应用安装和应用启动两个过程看其是如何实现的:
1、应用安装阶段(xwalk/application/tools/tizen/xwalk_package_installer.cc):
- bool PackageInstaller::Install(const base::FilePath& path, std::string* id) {
- ......
- FileDeleter tmp_path(install_temp_dir.Append(path.BaseName()), false);
- if (!base::DirectoryExists(path)) {
- if (tmp_path.path() != path &&
- !base::CopyFile(path, tmp_path.path()))
- return false;
- package = Package::Create(tmp_path.path());
- if (!package || !package->IsValid())
- return false;
- package->ExtractToTemporaryDir(&unpacked_dir);
- app_id = package->Id();
- } else {
- unpacked_dir = path;
- }
- ......
- xwalk::application::TizenSettingInfo* info =
- static_cast<xwalk::application::TizenSettingInfo*>(
- app_data->GetManifestData(widget_keys::kTizenSettingKey));
- if (info && info->encryption_enabled()) {
- // Generate encryption key.
- scoped_ptr<crypto::SymmetricKey> key(
- crypto::SymmetricKey::GenerateRandomKey(
- crypto::SymmetricKey::AES, 256));
- std::string str_key;
- key->GetRawKey(&str_key);
- std::string appId = app_data->ID();
- std::transform(appId.begin(), appId.end(), appId.begin(), tolower);
- scoped_ptr<char[], base::FreeDeleter> buffer =
- scoped_ptr<char[], base::FreeDeleter>(strdup(str_key.c_str()));
- const char* filename = appId.c_str();
- int ret = ssm_write_buffer(
- buffer.get(), str_key.size(),
- filename,
- SSM_FLAG_SECRET_OPERATION,
- filename);
- // Encrypt the resources if needed.
- base::FileEnumerator iter(app_dir, true, base::FileEnumerator::FILES);
- for (base::FilePath file_path = iter.Next();
- !file_path.empty();
- file_path = iter.Next()) {
- if (!ret && xwalk::application::RequiresEncryption(file_path) &&
- base::PathIsWritable(file_path)) {
- std::string content;
- std::string encrypted;
- if (!base::ReadFileToString(file_path, &content)) {
- LOG(ERROR) << "Failed to read " << file_path.MaybeAsASCII();
- return false;
- }
- if (!xwalk::application::EncryptData(content.data(),
- content.size(),
- str_key,
- &encrypted)
- || !base::WriteFile(file_path,
- encrypted.data(),
- encrypted.size())) {
- LOG(ERROR) << "Failed to encrypt " << file_path.MaybeAsASCII();
- return false;
- }
- }
- }
- }
- ......
- return true;
- }
复制代码
上述代码中忽略其他应用安装的校验逻辑,从中可以看出,首先将Tizen的Web APP(xpk或wgt格式)解压至临时目录,然后根据当前应用的配置信息(是否需要加密)决定是否对其进行加密,如果需要,则遍历其资源文件目录,对*.html,*.htm,*.js和*.css文件的文件内容进行AES256加密方式加密,最后删除临时文件目录:
- bool RequiresEncryption(const base::FilePath& file_path) {
- return EndsWith(file_path.value(), kHTMLFormat, false) ||
- EndsWith(file_path.value(), kHTMFormat, false) ||
- EndsWith(file_path.value(), kJSFormat, false) ||
- EndsWith(file_path.value(), kCSSFormat, false);
- }
复制代码
2、应用启动的资源加载阶段(xwalk/application/browser/application_protocols.cc): - #if defined(OS_TIZEN)
- void DidOpen(int result) {
- ......
- int rv = stream_->Read(
- cipher_buffer_.get(),
- cipher_buffer_->size(),
- base::Bind(&URLRequestApplicationJobTizen::DidReadEncryptedData,
- weak_ptr_factory_.GetWeakPtr(), cipher_buffer_));
- ......
- }
- void DidReadEncryptedData(scoped_refptr<net::IOBufferWithSize> buf,
- int result) {
- ......
- int ret = ssm_read(filename, data, sfi.originSize, &read_len,
- SSM_FLAG_SECRET_OPERATION, filename);
- std::string key_str(data, read_len);
- free(data);
- if (!ret && !DecryptData(buf->data(), buf->size(), key_str, &plain_text)) {
- ......
- return;
- }
- ......
- }
- #endif
复制代码
这里从加密文件中中获取到资源数据之后,通过DecryptData()方法执行解密过程(解密后的资源数据片段通过plain_text字串的方式添加在plain_buffer_中),之后通过ReadRawData()方法返回解密后的资源数据。
不知道能不能利用类似chrome远程调试工具的手段通过动态方式看到其代码,不过不难想到,这种方式也还是不能从根本上解决问题。 |
|