也许您可以使用基本的 CSRF 方法,并且每次请求只加载一次字体,创建一次使用后过期的会话密钥并检查引荐来源网址(如果用户在后续请求中清空那里可能会中断)。
但是对于一些待办事项;p 我已经整理了一个示例来说明我的意思,它不是 100%,但它会阻止公众尝试直接访问该字体。 download the source example
使用此方法,获取您需要的字体:
- 向页面发出请求,但不加载 css 字体。 (fgc,curl,ect)
- 解析页面源代码并从 CSS 中获取键。
-
然后向字体加载器发出自定义请求,设置引荐来源网址
并使用键值对。
CSS,你可以做的不是指向字体的路径,而是使用PHP来加载字体,这样你就可以在查询中添加一些nonce。
@font-face {
font-family: 'TheFontName';
src: local('TheFontName'), url('<?php echo SITE_URL.'/fonts.php?font=TheFontName.woff&'.$_SESSION['font_csrf_key'].'='.$_SESSION['font_csrf_token']?>') format('woff');
font-weight: normal;
font-style: normal;
}
示例(index.php)
<?php
/**
* @name ProtectFont
* @link https://www.dropbox.com/s/xsbpw4g3xn4fzai/ProtectFont.zip
*/
session_start();
//Define paths
define('BASE_FOLDER', dirname($_SERVER['SCRIPT_NAME']));
define('SITE_ROOT', pathinfo($_SERVER['SCRIPT_FILENAME'], PATHINFO_DIRNAME));
define('SITE_URL', rtrim( 'http://'.$_SERVER['HTTP_HOST'].BASE_FOLDER, '/'));
//Site host will be checked against as the referrer host
define('SITE_HOST', parse_url(SITE_URL, PHP_URL_HOST));
/* Now for the font protection, we create 2 CSRF keys,
one for the $_GET key and the other as the value.
*/
$_SESSION['font_csrf_key'] = sha1(uniqid());
$_SESSION['font_csrf_token'] = sha1(uniqid());
?>
<!DOCTYPE html>
<html>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<style>
@font-face {
font-family: 'TheFontName';
src: local('TheFontName'), url('<?php echo SITE_URL.'/fonts.php?font=TheFontName.woff&'.$_SESSION['font_csrf_key'].'='.$_SESSION['font_csrf_token']?>') format('woff');
font-weight: normal;
font-style: normal;
}
body {
font-size: 110%;
}
h1{
font-family: 'TheFontName',serif;
}
</style>
<body>
<h1>Your Font, try and nick me...</h1>
<p>This is the CSS thats on this page, the font is only accessible once for this request, if you try to link it will fail:<br>
<pre>
@font-face {
font-family: 'TheFontName';
src: local('TheFontName'), url(<span style="color:green">'<?php echo SITE_URL.'/fonts.php?font=TheFontName.woff&'.$_SESSION['font_csrf_key'].'='.$_SESSION['font_csrf_token']?></span>') format('woff');
font-weight: normal;
font-style: normal;
}
body {
font-size: 110%;
}
h1{
font-family: 'TheFontName',serif;
}
</pre>
<p>Using this method, to get the font you would need to:</p>
<ol>
<li>Make a request to this page, without loading the css font. Can be done with file_get_content, curl
ect.</li>
<li>Parse the pages source and get the <?php echo $_SESSION['font_csrf_key'].'='.$_SESSION['font_csrf_token']?> keys.</li>
<li>Make a request to the font loader using the above key value pairs </li>
<li>And set the referrer in that request to: <?php echo SITE_URL; ?></li>
</ol>
<p>Perhaps its enough to stop a few people but not everyone.</p>
<p>Where there's a will, there's a way... Anything
that your browser sees can be downloaded/saved. I don't know how they can expect
you todo this, they don't offer any reliable solution because then there not
liable for loss. 99.9% of your users wont think about taking the font. Others
will find a way...</p>
<p>Good luck</p>
</body>
</html>
现在我们进入 fonts.php 字体加载器,该文件仅在窗帘值匹配(CSRF 令牌和引用者)时加载字体,否则发送空白 404。
示例(fonts.php)
<?php
/**
* Font loader, this file will only load the font if curtain values match
*/
session_start();
//Define script our paths
define('BASE_FOLDER', dirname($_SERVER['SCRIPT_NAME']));
define('SITE_ROOT', pathinfo($_SERVER['SCRIPT_FILENAME'], PATHINFO_DIRNAME));
define('SITE_URL', rtrim( 'http://'.$_SERVER['HTTP_HOST'].BASE_FOLDER, '/'));
//This will be checked against as the passed referer
define('SITE_HOST', parse_url(SITE_URL, PHP_URL_HOST));
if(
//Check required variables are set
// -The tokens for the request
isset($_SESSION['font_csrf_key']) &&
isset($_SESSION['font_csrf_token']) &&
// -The font you want to load
isset($_GET['font']) &&
// -The $_GET request key
isset($_GET[$_SESSION['font_csrf_key']]) &&
// -The referer
isset($_SERVER["HTTP_REFERER"])&&
// - Validate session keys with the passed token
$_GET[$_SESSION['font_csrf_key']] == $_SESSION['font_csrf_token'] &&
// - Validate the Referer
parse_url($_SERVER["HTTP_REFERER"], PHP_URL_HOST) == SITE_HOST
){
//check font exists
if(file_exists(SITE_ROOT.'/_fonts/'.basename($_GET['font']))){
//no cache
header("Cache-control: no-store, no-cache, must-revalidate");
header("Expires: Mon, 26 Jun 1997 05:00:00 GMT");
header("Pragma: no-cache");
//I think this is the right header
header("Content-Type: application/octet-stream");
set_time_limit(0);
//ok nows lets load and send the font
$font = null;
$h = fopen(SITE_ROOT.'/_fonts/'.basename($_GET['font']), 'rb');
if($h){
while ($line = fgets($h, 4096)){
$font .= $line;
}
}else{
header("HTTP/1.0 404 Not Found");
}
fclose($h);
header('Content-Length: '.strlen($font));
echo $font;
}else{
header("HTTP/1.0 404 Not Found");
}
}
else{
header("HTTP/1.0 404 Not Found");
}
//Unset to stop second access
unset($_SESSION['font_csrf_key'], $_SESSION['font_csrf_token']);
?>
希望对您有所帮助,download the example source here。您还可以将 cookie 添加到保护中以添加额外的保护层。或者甚至将文件名TheFontName.woff 更改为会话密钥并将文件名的真实值存储在会话中,或者将其混合并在查询字符串中添加诱饵,您可以在会话中设置正确的值或顺序。要有创意,但最终它不是防弹的。祝你好运