处理HTTPS页面中的HTTP内容

时间:2010-06-10 02:17:57

标签: http image https

我们有一个完全通过HTTPS访问的网站,但有时会显示外部内容,即HTTP(主要来自RSS Feed的图片)。绝大多数用户也被困在IE6上。

我最好还是喜欢以下两个

  • 防止有关不安全内容的IE警告消息(以便我可以显示较少侵入性内容,例如使用默认图标替换图像,如下所示)
  • 向用户展示一些有用的东西,代替他们无法看到的图像;如果有一些JS,我可以找出哪些图像没有被加载,并用我们的图像替换它们,这将是伟大的。

我怀疑第一个目标根本不可能,但第二个目标可能就足够了。

最糟糕的情况是我在导入时解析RSS源,抓取图像将它们存储在本地,以便用户可以通过这种方式访问​​它们,但似乎很难获得相当大的收益。

10 个答案:

答案 0 :(得分:146)

你最糟糕的情况并不像你想象的那么糟糕。

您已在解析RSS Feed,因此您已拥有图片网址。假设您有一个像http://otherdomain.com/someimage.jpg这样的图片网址。您将此URL重写为https://mydomain.com/imageserver?url=http://otherdomain.com/someimage.jpg&hash=abcdeafad。这样,浏览器总是通过https发出请求,因此您可以解决问题。

下一部分 - 创建执行以下操作的代理页面或servlet -

  1. 从查询字符串中读取url参数,并验证哈希值
  2. 从服务器下载图像,并将其代理回浏览器
  3. (可选)将图像缓存在磁盘上
  4. 这种解决方案有一些优点。您不必在创建html时下载图像。您不必在本地存储图像。而且,你是无国籍的; url包含提供图像所需的所有信息。

    最后,hash参数用于安全性;您只希望您的servlet为您构建的URL提供图像。因此,在创建URL时,请计算md5(image_url + secret_key)并将其作为哈希参数附加。在您提供请求之前,请重新计算哈希值并将其与传递给您的哈希值进行比较。由于secret_key只为您所知,因此没有其他人可以构建有效的URL。

    如果您使用java进行开发,Servlet只需几行代码。您应该能够在任何其他后端技术上移植以下代码。

    /*
    targetURL is the url you get from RSS feeds
    request and response are wrt to the browser
    Assumes you have commons-io in your classpath
    */
    
    protected void proxyResponse (String targetURL, HttpServletRequest request,
     HttpServletResponse response) throws IOException {
        GetMethod get = new GetMethod(targetURL);
        get.setFollowRedirects(true);    
        /*
         * Proxy the request headers from the browser to the target server
         */
        Enumeration headers = request.getHeaderNames();
        while(headers!=null && headers.hasMoreElements())
        {
            String headerName = (String)headers.nextElement();
    
            String headerValue = request.getHeader(headerName);
    
            if(headerValue != null)
            {
                get.addRequestHeader(headerName, headerValue);
            }            
        }        
    
        /*Make a request to the target server*/
        m_httpClient.executeMethod(get);
        /*
         * Set the status code
         */
        response.setStatus(get.getStatusCode());
    
        /*
         * proxy the response headers to the browser
         */
        Header responseHeaders[] = get.getResponseHeaders();
        for(int i=0; i<responseHeaders.length; i++)
        {
            String headerName = responseHeaders[i].getName();
            String headerValue = responseHeaders[i].getValue();
    
            if(headerValue != null)
            {
                response.addHeader(headerName, headerValue);
            }
        }
    
        /*
         * Proxy the response body to the browser
         */
        InputStream in = get.getResponseBodyAsStream();
        OutputStream out = response.getOutputStream();
    
        /*
         * If the server sends a 204 not-modified response, the InputStream will be null.
         */
        if (in !=null) {
            IOUtils.copy(in, out);
        }    
    }
    

答案 1 :(得分:12)

如果您正在寻找通过HTTPS加载图片的快速解决方案,那么https://images.weserv.nl/的免费反向代理服务可能会让您感兴趣。这正是我想要的。

如果您正在寻找付费解决方案,我之前使用的Cloudinary.com也运行良好,但在我看来,这个任务太贵了。

答案 2 :(得分:3)

我不知道这是否符合您的要求,但作为快速修复,我会将http内容“包装”到https脚本中。例如,在通过https提供的页面上,我将引入一个iframe来替换你的RSS提要,并在iframe的src attr中放置一个脚本,在你的服务器上捕获feed并输出html。脚本通过http读取feed并通过https输出(因此“包装”)

只是一个想法

答案 3 :(得分:2)

关于你的第二个要求 - 你可能能够利用onerror事件,即。 <img onerror="some javascript;"...

更新

你也可以尝试在dom中迭代document.images。您可以使用complete布尔属性。我不确定这是否合适,但可能值得研究。

答案 4 :(得分:0)

最好只在https上提供http内容

答案 5 :(得分:0)

有时候,在Facebook应用中,我们无法在安全页面中拥有非安全内容。我们也不能把这些内容制作成本地。例如,将在iFrame中加载的应用程序不是简单的内容,我们无法将其设置为本地内容。

我认为我们永远不应该在https中加载http内容,我们也不应该将https页面回退到http版本以防止错误对话。

确保用户安全的唯一方法是使用所有内容的https版本,http://developers.facebook.com/blog/post/499/

答案 6 :(得分:0)

接受的答案帮助我更新了PHP和CORS,所以我想我会为其他人提供解决方案:

纯PHP / HTML:

<?php // (the originating page, where you want to show the image)
// set your image location in whatever manner you need
$imageLocation = "http://example.com/exampleImage.png";

// set the location of your 'imageserve' program
$imageserveLocation = "https://example.com/imageserve.php";

// we'll look at the imageLocation and if it is already https, don't do anything, but if it is http, then run it through imageserve.php
$imageURL = (strstr("https://",$imageLocation)?"": $imageserveLocation . "?image=") . $imageLocation;

?>
<!-- this is the HTML image -->
<img src="<?php echo $imageURL ?>" />

的javascript / jQuery的:

<img id="theImage" src="" />
<script>
    var imageLocation = "http://example.com/exampleImage.png";
    var imageserveLocation = "https://example.com/imageserve.php";
    var imageURL = ((imageLocation.indexOf("https://") !== -1) ? "" : imageserveLocation + "?image=") + imageLocation;
    // I'm using jQuery, but you can use just javascript...        
    $("#theImage").prop('src',imageURL);
</script>

imageserve.php 有关CORS的更多信息,请参阅http://stackoverflow.com/questions/8719276/cors-with-php-headers?noredirect=1&lq=1

<?php
// set your secure site URL here (where you are showing the images)
$mySecureSite = "https://example.com";

// here, you can set what kinds of images you will accept
$supported_images = array('png','jpeg','jpg','gif','ico');

// this is an ultra-minimal CORS - sending trusted data to yourself 
header("Access-Control-Allow-Origin: $mySecureSite");

$parts = pathinfo($_GET['image']);
$extension = $parts['extension'];
if(in_array($extension,$supported_images)) {
    header("Content-Type: image/$extension");
    $image = file_get_contents($_GET['image']);
    echo $image;
}

答案 7 :(得分:-2)

简单地说:不要做。 HTTPS页面中的Http内容本质上是不安全的。点。这就是IE显示警告的原因。摆脱警告是一种愚蠢的h水手法。

相反,HTTPS页面应具有HTTPS内容。确保内容也可以通过HTTPS加载,如果页面是通过https加载的,则通过https引用。对于外部内容,这将意味着在本地加载和缓存元素,以便通过https - 确保它们可用。遗憾的是,没办法解决这个问题。

警告是有充分理由的。认真。花5分钟思考如何接管带有自定义内容的https显示页面 - 你会感到惊讶。

答案 8 :(得分:-3)

我意识到这是一个旧线程但只有一个选项就是从图片网址中删除http:部分,以便&#39; http://some/image.jpg&#39;成为&#39; // some / image.jpg&#39;。这也适用于CDN

答案 9 :(得分:-3)

最适合我的方式

<img src="/path/image.png" />// this work only online
    or
    <img src="../../path/image.png" /> // this work both
    or asign variable
    <?php 
    $base_url = '';
    if($_SERVER['HTTP_HOST'] == 'localhost')
    {
         $base_url = 'localpath'; 
    }
    ?>
    <img src="<?php echo $base_url;?>/path/image.png" />