如何保护网页字体?

时间:2014-01-30 23:59:48

标签: php svg fonts webfonts protection

我的客户已经购买了我想在他的网站上使用的字体,但制作该字体的公司(Adobe)告诉我,这个当前字体没有webfont服务,我可以在网站上使用它只有当我光栅化它或者无法以任何其他方式下载/窃取字体时。

因此,问题是:

有没有可靠的方法来保护网络字体?

(第二,可选部分)

有什么方法通常被认为是足够的,以便在使用字体时合法安全吗?

到目前为止我学到了什么:

1)我听说使用SVG文件的Cufon(根据w3.org)用于此目的:

  

SVG字体的目的是允许传递字形轮廓   仅显示环境。伴随网页的SVG字体必须是   仅在浏览和查看情况下受支持。图形编辑   应用程序或文件转换工具不得尝试转换SVG   字体变成系统字体。意图是SVG文件   可在两个内容创建者之间互换,但不能在SVG字体之间互换   可能伴随这些SVG文件。相反,每个内容创建者   在成功之前需要许可给定的字体   编辑SVG文件。

但我也看到很少从SVG到普通字体格式的在线转换器(还没有真正尝试过它们)。

2)我也看到了这个线程,它说它不完全可能,但它已经两年了,也许技术已经提前了: How to protect WebFonts

3)我也相信PDF有一些方法可以让它无法提取字体,几年前我看到PDF无法提取文本(即使使用第三方工具),因为有故意混淆字体表因此我必须将整个文档渲染成图像并使用OCR。但是,这可能不是这种情况,因为我试图提取文本而不是字体。

4)字体销售公司必须以某种方式保护他们的字体(?)

4 个答案:

答案 0 :(得分:2)

从根本上说,如果你打算在不使用图像的情况下使用该字体(这是一种可怕的做法,如果你在页面上谈论的不仅仅是几个字符就应该避免!)你无法阻止人们进行逆向工程你的字体。例如,像Cufon那样将它们处理为SVGcanvas(或SVGVML)会迫使用户做一些工作,如果他们想要偷它,但那里是plenty of SVG->TFF converters out there

即使没有转换器,您仍然可以根据SVG定义的向量创建新的字体集。防止这种情况的唯一方法是不提供任何基于矢量的字体系统(即使用位图),但这基本上会破坏您网站的可访问性。即便如此,如果你已经编写了一个动态系统来提供基于图像的字体,如果你让用户拥有足够高分辨率的图像位图(即服务器是一个大字体),那么有些脚本可以将轮廓转换为载体

字体销售公司(至少是我见过的公司)都只提供用于预览的字体的基于图像的版本,并限制了您可以演示的字体的最大尺寸。

答案 1 :(得分:2)

也许您可以使用基本的CSRF方法,并且每次请求只加载一次字体,创建一次使用后过期的会话密钥并检查引用者(如果用户在后续请求中清空,则可能会中断)。

但对于todo; p我已经把我的意思放在一个例子,它不是100%,但它会阻止一般公众试图直接访问字体。 download the source example

使用此方法,获取您需要的字体:

  1. 向页面发出请求,而不加载css字体。 (FGC,卷曲,ECT)
  2. 解析页面源并从CSS获取密钥。
  3. 然后对字体加载器发出自定义请求,设置引荐来源 并使用键值对。

    • 也许它会通过那里的保护期望。
  4. CSS,您可以做的不是将路径指向字体,而是使用PHP加载字体,这样您就可以在查询中添加一些随机数。

    @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更改为会话密钥并在会话中存储文件名的实际值,或者将其混合并在查询字符串中添加诱饵,您可以在会话中设置哪个是正确的值或顺序。要有创意,但最后它不是防弹。祝你好运

答案 2 :(得分:1)

无法阻止字体被反向编码为任何格式。在某些格式(如TTF)中有版权信息,但在线转换器可以自由忽略它们。

但是,您可以使字体使用起来相对不切实际,即使其对潜在的黑客不再具有吸引力。

例如,如果您知道您的页面不会使用某些字符,则可以将其缩小为真实字形的子集。我不是指将字体拆分成子部分。我的意思是不提供您网站上未使用的任何字形。例如,如果您的网站是英文网站,请删除所有变音符号或非拉丁语字符集。

此外,在使用某些格式(例如,SVG字体是裸字形)时,一些精炼的信息(如字距调整和提示)会丢失。将它们反向编码为TTF将产生一个穷人的原始字体版本。

另一方面,对于小字体,SVG输出相当差。在伤害盗贼之前使用SVG可能会伤害您的网站。

答案 3 :(得分:1)

可能没有合法安全的方法来执行此操作,因为即使是字体的精简版仍将包含受版权保护的信息,并且可以规避任何其他保护措施。

如果字体不提供带有较少压迫性术语的显式Web许可证,最好不要在网络上使用它,除了以光栅化图像的形式。周期。

我会看到像Google Fonts这样的服务是否提供了外观相似的字体。

您还可以到处查看不同的字体许可方是否为相同或至少类似外观的字体提供Web许可。像Identifont这样的字体标识符可以帮助您找到类似的标识符。