温馨提示:
本文所述内容具有依赖性,可能因软硬条件不同而与预期有所差异,故请以实际为准,仅供参考。
安全浏览(Safe Browsing)是 Google 的安全团队打造的一项服务,旨在发现网上的不安全网站并将潜在危害告知用户和网站站长,具体介绍可以参考官方网页。简单来说就是 Google 的安全浏览服务会检查数十亿个网址以及相应网页中的软件和内容,发现其中包含病毒、网站被篡改等不安全问题,并在用户访问时发出警告,这是一项很有用的服务,故考虑将其集成到网站外链处理中,当用户点击外链时实时进行检测提醒。
集成使用安全浏览服务可以有两种方式,一种是直接抓取安全浏览检测网页的内容,判断返回的状态:
这种方法可以实现目标,但效率一般,不在本文探讨中;另一种方法是使用 Google 提供的 Safe Browsing API,这种方法相比前一种更为高效,故我们接下来一起来看看如何利用 API 的方式来集成安全浏览服务。
注意,不管是哪种方法,都要求运行此服务的主机能够访问 Google 网站。
注册
注册账号
使用 Safe Browsing API 要求必须要有谷歌(Google)账号,因此在进行下一步前请先注册账号,可以使用自己的邮箱注册,这里就不详细介绍,按页面提示操作即可:
注册 API
打开 Google Developers Console API 库,从项目下拉列表中,选择一个项目或创建一个新项目,由于现在 API 已经集成到 Google Cloud Platform,创建项目前可能需要先绑定有效的付款方式(API 不收费):
在 Google API 标签中,搜索并选择 Safe Browsing API ,注意有两个 API,我们选择新版 v4 的:
然后单击启用 API:
接下来,我们启用凭据:
选择安全浏览 Safe Browsing API,创建:
凭据已创建,记下来备用:
为保证凭据安全,建议进行使用限制,比如来源页、允许 IP 等:
到这里 API 凭据 KEY 已经成功获取。
使用
CURL 及参数解析
获得 KEY 后我们可以先测试一下效果:
$ curl -X POST \
'https://safebrowsing.googleapis.com/v4/threatMatches:find?key=YOUR_KEY_HERE' \
-H 'cache-control: no-cache' \
-H 'content-type: application/json' \
-d ' {
"client": {
"clientId": "vcloud",
"clientVersion": "1.1.1"
},
"threatInfo": {
"threatTypes": ["MALWARE", "SOCIAL_ENGINEERING"],
"platformTypes": ["WINDOWS"],
"threatEntryTypes": ["URL"],
"threatEntries": [
{"url": "https://accounts-wallets.redirectme.net/webapps/57a39/websrc"},
{"url": "http://stackoverflow.com/"}
]
}
}'
得到了如下响应:
{
"matches": [
{
"threatType": "SOCIAL_ENGINEERING",
"platformType": "WINDOWS",
"threat": {
"url": "https://accounts-wallets.redirectme.net/webapps/57a39/websrc"
},
"cacheDuration": "300s",
"threatEntryType": "URL"
}
]
}
我们提交了两条 URL 检测,但只回复了一条,说明如果网址是安全的,那么回复的内容为空,后续我们就可以以此来判断是否安全。
我们看一下请求的 JSON 参数:
{
"client": {
"clientId": "vcloud",
"clientVersion": "1.1.1"
},
"threatInfo": {
"threatTypes": ["MALWARE", "SOCIAL_ENGINEERING"],
"platformTypes": ["WINDOWS"],
"threatEntryTypes": ["URL"],
"threatEntries": [
{"url": "https://accounts-wallets.redirectme.net/webapps/57a39/websrc"},
{"url": "http://stackoverflow.com/"}
]
}
}
client
表示与安全浏览 API 请求关联的客户端元数据,可以根据自己需求实际设置:
clientId
表示使用 Safe Browsing API 的客户端唯一标识 ID,clientVersion
表示客户端版本。
threatInfo
表示要进行安全检测匹配的内容:
threatTypes:安全问题类型,主要有:
THREAT_TYPE_UNSPECIFIED | 未知的威胁类型 |
MALWARE | 恶意软件威胁类型 |
SOCIAL_ENGINEERING | 社会工程威胁类型 |
UNWANTED_SOFTWARE | 不需要的软件威胁类型 |
POTENTIALLY_HARMFUL_APPLICATION | 潜在有害的应用程序威胁类型 |
这也印证刚说的,如果检测是安全的,不会直接返回安全,而是不回复任何内容,凡有回复内容皆是存在安全风险。
platformTypes:安全问题平台,主要有:
PLATFORM_TYPE_UNSPECIFIED | 未知的平台 |
WINDOWS | 对 Windows 构成威胁 |
LINUX | 对 Linux 构成威胁 |
ANDROID | 对 Android 构成威胁 |
OSX | 对 OS X 构成威胁 |
IOS | 对 iOS 构成了威胁 |
ANY_PLATFORM | 对至少一个已定义的平台构成威胁 |
ALL_PLATFORMS | 对所有已定义的平台构成威胁 |
CHROME | 对 Chrome 构成威胁 |
threatEntryType:构成威胁的类型,区别于 threatTypes 和 platformTypes,一次只能指定一个:
THREAT_ENTRY_TYPE_UNSPECIFIED | 未指定 |
URL | 一个URL |
EXECUTABLE | 可执行程序 |
threatEntries(threatEntry):需要检测的目标,可以是 URL,也可以是哈希值,但一个JSON 中只能有一个(可以有多个 JSON):
hash | 二进制格式,对于 JSON 请求,哈希值由 base64 编码 |
url | 完整的 URL(无需编码) |
digest | 二进制或十六进制,针对可执行文件,对于 JSON 请求,哈希值由 base64 编码 |
再来看一下回复的 ThreatMatch JSON 参数:
{
"matches": [
{
"threatType": "SOCIAL_ENGINEERING",
"platformType": "WINDOWS",
"threat": {
"url": "https://accounts-wallets.redirectme.net/webapps/57a39/websrc"
},
"cacheDuration": "300s",
"threatEntryType": "URL"
}
]
}
其中 threatType
、platformType
在请求 JSON 已经讲过了;threat
表示匹配到的请求 JSON 中的 threatEntries
中的有安全风险的条目;cacheDuration
表示该匹配的缓存生存期,客户端若有缓存安全警报,则缓存时间不应超过此时间以避免误报;threatEntryType
则表示检测的 threat
的类型。
之所以将 JSON 参数讲解这么详细,是因为我们可以根据需要指定检测特定的安全类型、平台、URL 等等,以提高效率。
Python 示例
import requests
url = "https://safebrowsing.googleapis.com/v4/threatMatches:find"
querystring = {"key":"YOUR_KEY"}
payload = """
{
"client": {
"clientId": "yourcompanyname",
"clientVersion": "1.5.2"
},
"threatInfo": {
"threatTypes": ["MALWARE", "SOCIAL_ENGINEERING"],
"platformTypes": ["WINDOWS"],
"threatEntryTypes": ["URL"],
"threatEntries": [
{"url": "https://accounts-wallets.redirectme.net/webapps/57a39/websrc"},
{"url": "http://stackoverflow.com/"}
]
}
}
"""
headers = {
'content-type': "application/json",
'cache-control': "no-cache",
'postman-token': "460d6d44-4a55-d6ab-fb58-2ff9fb306154"
}
response = requests.request("POST", url, data=payload, headers=headers, params=querystring)
print(response.text)
PHP 示例
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://safebrowsing.googleapis.com/v4/threatMatches:find?key=YOUR_KEY",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => " {
"client": {
"clientId": "yourcompanyname",
"clientVersion": "1.5.2"
},
"threatInfo": {
"threatTypes": ["MALWARE", "SOCIAL_ENGINEERING"],
"platformTypes": ["WINDOWS"],
"threatEntryTypes": ["URL"],
"threatEntries": [
{"url": "https://accounts-wallets.redirectme.net/webapps/57a39/websrc"},
{"url": "http://stackoverflow.com/"}
]
}
}",
CURLOPT_HTTPHEADER => array(
"cache-control: no-cache",
"content-type: application/json",
"postman-token: b05b8d34-85f2-49cf-0f8e-03686a71e4e9"
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}
?>
Typecho
参照本站代码:
function.php(供参考,不要直接照抄):
......
function safeCheck($url){
if(!isset($url) || empty($url)){
return 'ERROR: URL is required.';
}
if(!isset(Helper::options()->safeapi) || empty(Helper::options()->safeapi)){
return 'ERROR: API Key is required.';
} else {
$apiKey = Helper::options()->safeapi;
}
if(!isset($_SERVER['HTTP_USER_AGENT']) || empty($_SERVER['HTTP_USER_AGENT'])){
return 'ERROR: Unknown platform.';
} else {
$os = getOS($_SERVER['HTTP_USER_AGENT'], 1);
if(strpos($os,'Windows') === true) {
$platform = 'WINDOWS';
} elseif(strpos($os,'Linux') === true) {
$platform = 'LINUX';
} elseif(strpos($os,'Android') === true) {
$platform = 'ANDROID';
} else {
$platform = 'IOS';
}
}
$apiUrl = 'https://safebrowsing.googleapis.com/v4/threatMatches:find?key='.$apiKey;
$params = [
'client' => [
'clientId' => 'armxmod',
'clientVersion' => '7.2.0'
],
'threatInfo' => [
'threatTypes' =>['MALWARE', 'SOCIAL_ENGINEERING'],
'platformTypes' => $platform,
'threatEntryTypes' => ['URL'],
'threatEntries' => [
[ 'url' => $url ]
]
]
];
$curl = curl_init($apiUrl);
curl_setopt_array($curl, array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 3,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_POSTFIELDS => json_encode($params),
CURLOPT_HTTPHEADER => array(
'cache-control: no-cache',
'content-type: application/json'
),
));
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
return 'ERROR: ' . $err;
} else {
$res = json_decode($response,true);
if ($res['error']['message']){
return $res['error']['message'];
} else if($res['matches']['threatType']){
return $res['matches']['threatType'];
} else {
return 'safe';
}
}
}
......
在需要检测的地方,使用如下代码即可:
......
<?php echo '安全检测结果:'.safeCheck($url);?>
......
注意
Safe Broswing API 是有调用限制的,所以要注意 KEY 的调用限制:
Requests per day(每天):10,000 次
Requests per 100 seconds per user(100 秒内):3,000 次
另外,API KEY 似乎只有 24 小时有效期(测试中出现了 API key expired. Please renew the API key
错误),暂时没看到哪里可以设置永久的,知道的朋友可以告知一下,感谢。
参考文章:
1、《官方 API 说明:Safe Browsing API》
2、《PHP check website url using safe browsing API》
Windows 10Chrome 80.0.3987.149来自 江苏 的大神
谢谢分享
Ubuntu LinuxFirefox 67.0来自 湖北 的大神
看了一下,还挺好用的,不过都是PHP代码格式的,而我是Hexo的
大致方法思路是类似的
LinuxChrome 85.0.4183.102来自 河南 的大神
被注册API难住了。。
难道又改版了?GCP 后台经常改,入口名字可能不太一样,但总体上还是差不多的
LinuxFirefox 60.0来自 河南 的大神
不是,没信用卡惹
Windows 10Chrome 125.0.0.0来自 中国 的大神
申请 GCP API 并不需要信用卡,只要强制进入 GCP 的 Project 就好了