【问题标题】:Dealing with HTTP content in HTTPS pages处理 HTTPS 页面中的 HTTP 内容
【发布时间】:2011-03-01 23:20:40
【问题描述】:

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

理想情况下,我想做以下两件事

  • 防止出现关于不安全内容的 IE 警告消息(这样我就可以显示较少干扰的警告消息,例如,将图像替换为如下的默认图标)
  • 向用户展示一些有用的东西来代替他们无法看到的图像;如果有一些 JS,我可以运行以找出哪些图像尚未加载并用我们的图像替换它们,那就太好了。

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

最糟糕的情况是,我在导入 RSS 提要时解析它们,获取存储在本地的图像,以便用户可以通过这种方式访问​​它们,但这似乎很痛苦,但收获却很少。

【问题讨论】:

    标签: http image https


    【解决方案1】:

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

    只是一个想法

    【讨论】:

    • 在我看来,这会让我处于和现在一样的境地;我已经在 HTTPS 页面中显示了内容 - 问题是内容中有 标记带有 http:// src 值 - 这些标记没有显示并导致出现烦人的消息。
    • 嗯,是的,如果您保留图片的原始链接,则无法避免此问题。包装脚本必须扫描 rss 提要内容中的图像并将其删除。正如您在另一条评论中提到的 - 您不想加载导致弹出窗口的内容并显示一些信息。这就是“中间脚本”的原因
    • 您甚至可以在没有 iframe 的情况下直接在您的主后端脚本中执行此操作,但在这种情况下,您正在等待 rss 提要返回,然后再被处理并输出到页面上。我会做一个 iFrame,以便您的页面与 rss 提要异步加载。如果你想去那里避免 iframe,还有 ajax 选项。只是好奇 - 你的后端平台是什么?
    【解决方案2】:

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

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

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

    【讨论】:

    • 很容易,我知道这样做是有充分理由的;我认为IE在这方面的表现比FF好。我的目标是加载内容;我只是想避免侵入性弹出式警告,并显示一些信息代替内容。
    • 没有机会 - 除非您在退出时重写 HTML。任何 javascript 后加载尝试都已显示该对话框。
    • 他只是询问图像,并没有请求任何不安全的文本或脚本,因此我们可以通过重写 url 来绕过警告。
    • 答案没有变化。图像也可能不安全。这是一个普遍的事情 - 要么它来自安全的来源,要么它可能被中间攻击的人所取代。
    • 投反对票,因为这个 "answer" 没有回答如何实现 OP 的目标。
    【解决方案3】:

    关于您的第二个要求 - 您也许可以利用 onerror 事件,即。 <img onerror="some javascript;"...

    更新:

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

    【讨论】:

    • 有趣,我什至不知道一个onerror事件。我必须重写 HTML(因为它来自外部源),但它已经用 HTML 净化器进行了清理,因此可以将其添加为过滤器。
    • 在 JavaScript 有机会做任何事情之前不会出现任何浏览器安全警告吗?
    【解决方案4】:

    最好只在 https 上有 http 内容

    【讨论】:

    • 如果我没有在我的问题中明确说明,HTTP 内容在其他人的服务器上,而不是我的。具体来说,是我从 RSS 提要中检索到的 HTML 中的 链接。我现在在问题中强调了这一点。
    • 哦,好的,webproworld.com/webmaster-forum/threads/… 有帮助吗?
    【解决方案5】:

    你最坏的情况并没有你想象的那么糟糕。

    您已经在解析 RSS 提要,因此您已经有了图片 URL。假设您有一个图像 URL,例如 http://otherdomain.com/someimage.jpg。您将此 URL 重写为 https://mydomain.com/imageserver?url=http://otherdomain.com/someimage.jpg&hash=abcdeafad。这样,浏览器总是通过 https 发出请求,因此您摆脱了这些问题。

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

    1. 从查询字符串中读取url参数,验证hash
    2. 从服务器下载图片,并将其代理回浏览器
    3. (可选)将图像缓存在磁盘上

    这个解决方案有一些优点。您不必在创建 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);
        }    
    }
    

    【讨论】:

    • 非常好听,我想这就是我想要的。我们正在使用 PHP,但实现也很简单。我还将在我们这边实现缓存,因为我不想每次有人请求时都下载图像(为了性能和带宽使用)。安全方法的建议也是合理的(尽管我们也将应用我们的标准安全模型以及上述)。感谢您的建议。
    • 这种方法的唯一严重缺点是您通过自己的系统路由所有外部资源。这不仅是一种责任,而且可能会变得相当昂贵。
    • 我支持@TimMolendijk,并补充说它不仅增加了成本和维护,而且还击败了任何应该路由到附近服务器或平衡到空闲服务器的 CDN。
    • NodeJS 的解决方案是什么?
    • @TimMolendijk 的另一个 +1 但那会是什么解决方案呢?通过 HTTPS 提供的网站似乎无法很好地处理通过 HTTP 传递的图像
    【解决方案6】:

    有时就像在 facebook 应用程序中一样,我们不能在安全页面中包含不安全的内容。我们也不能将这些内容本地化。例如,将在 iFrame 中加载的应用不是简单的内容,我们不能将其本地化。

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

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

    【讨论】:

    • 这可能在 facebook 上可行,但并非针对所有内容,而且这个问题与 facebook 无关。
    【解决方案7】:

    我意识到这是一个旧线程,但一种选择是从图像 URL 中删除 http: 部分,以便“http://some/image.jpg”变为“//some/image.jpg”。这也适用于 CDN

    【讨论】:

    • 这有时有效,有时无效;这取决于上游内容是否可以通过 HTTPS 获得。如果没有,它就会崩溃。
    【解决方案8】:

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

    如果您正在寻找付费解决方案,我之前使用过 Cloudinary.com,它也很有效,但在我看来,仅完成这项任务就太贵了。

    【讨论】:

    • 有什么收获?效果很好
    • @JackNicholson 我已经在相对较重的负载下使用它 2 年了。效果很好!向两位开发者致敬。
    • 我有一些以 Http 开头的链接(视频或网站),但我无法在我们的 https 网站上的 iframe 中显示它们。由于这是非安全链接,因此无法正常工作。对于图像,我已经使用图像缓存解决了这个问题。大家有什么想法
    • @int14 你需要为 http 站点设置一个反向代理,你可以使用 AWS API Gateway 之类的东西。
    【解决方案9】:

    最适合我的工作方式

    <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" /> 
    

    【讨论】:

      【解决方案10】:

      接受的答案帮助我将其更新为 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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-04-21
        • 1970-01-01
        • 1970-01-01
        • 2013-08-15
        • 1970-01-01
        • 1970-01-01
        • 2015-07-21
        • 1970-01-01
        相关资源
        最近更新 更多