Работа с HTTP-контентом на HTTPS-страницах

У нас есть сайт, доступ к которому осуществляется полностью по HTTPS, но иногда отображается внешний контент, который является HTTP (изображения из RSS-каналов, в основном). Подавляющее большинство наших пользователей также застряли на IE6.

В идеале я хотел бы сделать оба следующих

  • Предотвратите предупреждение IE о небезопасном контенте (чтобы я мог показывать менее навязчивый, например, заменяя изображения значком по умолчанию, как показано ниже)
  • Представьте что-то полезное для пользователей вместо изображений, которые они иначе не видят; если бы был какой-то JS, я мог бы запустить, чтобы выяснить, какие изображения не были загружены и заменить их своим изображением, а это было бы здорово.

Я подозреваю, что первая цель просто невозможна, но вторая может быть достаточной.

Худший сценарий заключается в том, что я разбираю RSS-каналы, когда мы их импортируем, захватываем изображения, сохраняя их локально, чтобы пользователи могли получить к ним доступ таким образом, но кажется, что это очень больно для разумно малого выигрыша.

Ответ 1

Ваш худший сценарий не так плох, как вы думаете.

Вы уже разбираете RSS-канал, поэтому у вас уже есть URL-адреса изображений. Скажем, у вас есть URL-адрес изображения, например http://otherdomain.com/someimage.jpg. Вы переписываете этот URL как https://mydomain.com/imageserver?url=http://otherdomain.com/someimage.jpg&hash=abcdeafad. Таким образом, браузер всегда делает запрос по https, поэтому вы избавляетесь от проблем.

Следующая часть - создайте прокси-страницу или сервлет, который выполняет следующие действия:

  • Прочитайте параметр url из строки запроса и проверьте hash
  • Загрузите изображение с сервера и прокси-сервер обратно в браузер
  • При необходимости кешируйте изображение на диске

Это решение имеет некоторые преимущества. Вам не нужно загружать изображение во время создания html. Вам не нужно сохранять изображения локально. Кроме того, вы без гражданства; url содержит всю информацию, необходимую для обслуживания изображения.

Наконец, хеш-параметр предназначен для безопасности; вы хотите, чтобы ваш сервлет служил изображениям для созданных вами 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);
    }    
}

Ответ 2

Если вы ищете быстрое решение для загрузки изображений по HTTPS, то вам может заинтересовать бесплатный сервис обратного прокси по адресу https://images.weserv.nl/. Это было именно то, что я искал.

Если вы ищете платное решение, я ранее использовал Cloudinary.com, который также хорошо работает, но, на мой взгляд, является слишком дорогим исключительно для этой задачи.

Ответ 3

Я не знаю, соответствовало бы тому, что вы делаете, но в качестве быстрого исправления я бы "обернул" содержимое http в https script. Например, на вашей странице, которая подается через https, я бы представил iframe, который заменил бы ваш rss-канал, а в src attr iframe поместил URL-адрес script на ваш сервер, который захватывает фид и выводит html. script читает канал через http и выводит его через https (таким образом, "обертывание" )

Просто мысль

Ответ 4

Что касается вашего второго требования - вы можете использовать событие onerror, т.е. <img onerror="some javascript;"...

Update:

Вы также можете попробовать выполнить итерацию через document.images в dom. Существует complete boolean свойство, которое вы, возможно, сможете использовать. Я не знаю точно, будет ли это подходящим, но, возможно, стоит исследовать.

Ответ 5

Было бы лучше всего иметь http-контент на https

Ответ 6

Иногда, как в приложениях facebook, у нас не может быть защищенного содержимого на защищенной странице. также мы не можем сделать локальное содержание. например, приложение, которое будет загружаться в iFrame, не является простым контентом, и мы не можем сделать его локальным.

Я думаю, что мы никогда не должны загружать содержимое HTTP в https, также мы не должны отбрасывать страницу https на http-версию, чтобы предотвратить диалоговое окно ошибок.

единственный способ обеспечить безопасность пользователя - использовать версию https всего содержимого, http://developers.facebook.com/blog/post/499/

Ответ 7

Принятый ответ помог мне обновить его как для 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 смотрите http://stackoverflow.com/questions/8719276/cors-with-php-headers?noredirect=1&lq=1 для получения дополнительной информации о CORS

<?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;
}

Ответ 8

Просто: НЕ ДЕЛАЙТЕ ЭТО. Содержание Http на странице HTTPS по своей сути небезопасно. Точка. Вот почему IE показывает предупреждение. Избавление от предупреждения - это глупый подход к хищничеству.

Вместо этого на странице HTTPS должно быть только содержимое HTTPS. Убедитесь, что содержимое может быть загружено также через HTTPS, и ссылаться на него через https, если страница загружается через https. Для внешнего контента это будет означать загрузку и кеширование элементов локально, чтобы они были доступны через https-sure. К сожалению, нет.

Предупреждение существует по уважительной причине. Шутки в сторону. Потратьте 5 минут на то, как вы можете взять страницу с показанной https с помощью специального контента - вы будете удивлены.

Ответ 9

Я понимаю, что это старый поток, но один из них - просто удалить http: часть из URL-адреса изображения, чтобы http://some/image.jpg 'становится'//some/image.jpg '. Это также будет работать с CDN

Ответ 10

Лучший способ работы для меня

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