Робота з вмістом HTTP на сторінках HTTPS


89

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

Я в ідеалі хотів би зробити наступне

  • Запобігання попереджувальному повідомленню IE про незахищений вміст (щоб я міг показати менш нав'язливий, наприклад, замінивши зображення на піктограму за замовчуванням, як показано нижче)
  • Подаруйте щось корисне користувачам замість зображень, які вони інакше не бачать; якби був якийсь JS, я міг би запустити, щоб з'ясувати, які зображення не завантажені, і замінити їх на наше зображення, натомість це було б чудово.

Я підозрюю, що перша мета просто неможлива, але другої може бути достатньо.

Найгірший сценарій полягає в тому, що я аналізую RSS-канали, коли ми їх імпортуємо, захоплюю зображення, щоб зберігати їх локально, щоб користувачі мали доступ до них таким чином, але це здається великим болем за досить невеликий прибуток.

Відповіді:


147

Ваш найгірший сценарій не такий поганий, як ви думаєте.

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

Наступна частина - створіть проксі-сторінку або сервлет, який робить наступне -

  1. Прочитайте параметр url із рядка запиту та перевірте хеш
  2. Завантажте зображення із сервера та поверніть його до браузера
  3. За бажанням кешуйте зображення на диску

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

Нарешті, параметр хеш призначений для безпеки; ви хочете, щоб ваш сервлет обслуговував зображення для створених вами URL-адрес. Отже, коли ви створюєте URL-адресу, обчислітьmd5(image_url + 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
Дуже звук, і я думаю, що це те, з чим я буду кататися. Ми використовуємо PHP, але реалізація також буде тривіальною. Я також застосую кешування на нашій стороні, оскільки не хочу завантажувати зображення кожного разу, коли хтось запитує його (для продуктивності та використання пропускної здатності). Пропозиції щодо підходу до безпеки слушні (хоча ми також застосовуватимемо нашу стандартну модель безпеки, а також вищезазначену). Дякуємо за вашу пропозицію.
El Yobo,

32
Єдиним серйозним недоліком цього підходу є те, що ви направляєте всі зовнішні ресурси через власні системи. Що є не тільки відповідальністю, але й може стати досить дорогим.
Тім Молендейк

Я зазначаю @TimMolendijk, додаючи, що він не тільки додає витрати та обслуговування, але і перешкоджає будь-яким CDN, які мали би спрямовуватися на близькі сервери або балансувати на непрацюючі.
Левенте Панчел

2
Яке рішення для NodeJS?
stkvtflw

1
ще +1 для @TimMolendijk, але що було б рішенням тоді? сайт, що обслуговується через HTTPS, схоже, не грає добре із зображеннями, доставленими через HTTP
FullStackForger

15

Якщо ви шукаєте швидке рішення для завантаження зображень через HTTPS, то безкоштовна послуга зворотного проксі-сервера за адресою https://images.weserv.nl/ може вас зацікавити. Це було саме те, що я шукав.

Якщо ви шукаєте платне рішення, я раніше використовував Cloudinary.com, який також добре працює, але є надто дорогим виключно для цього завдання, на мій погляд.


У чому суть? Чудово працює
Джек

5
@JackNicholson Я використовую його під відносно великим навантаженням вже 2 роки. Чудово працює! Похвала двом розробникам.
онульований

У мене є кілька посилань (відео чи сайт), що починаються з Http, і я не можу відобразити їх у iframe на нашому https-сайті. Оскільки це небезпечне посилання, воно не працює. для зображення я вирішив проблему за допомогою кешу зображень. У когось є якась ідея
int14

@ int14 Вам потрібно буде встановити зворотний проксі-сервер для сайту http, ви можете зробити це за допомогою чогось на зразок шлюзу API AWS.
обнуляти

3

Не знаю, чи відповідало б це тому, що ви робите, але для швидкого виправлення я б "загорнув" вміст http у сценарій https. Наприклад, на вашій сторінці, яка обслуговується через https, я ввів би iframe, який би замінив ваш RSS-канал, а в src attr iframe-а розмістив URL-адресу сценарію на вашому сервері, який фіксує канал і виводить html. сценарій читає стрічку через http і виводить її через https (таким чином, "обертаючи")

Просто думка


Мені здається, що це залишило б мене в тій самій ситуації, що і зараз; Я вже показую вміст на сторінці HTTPS - проблема полягає в тому, що у вмісті є теги <img> зі значеннями http: // src - які не відображаються і викликають прикрі повідомлення.
El Yobo

ну так, якщо ви зберігаєте оригінальні посилання на зображення, неможливо уникнути проблеми. Сценарію обгортки доведеться сканувати вміст RSS-стрічки на наявність зображень і видалити їх. Як ви вже згадували в іншому коментарі, ви не хочете завантажувати вміст, що викликає спливаюче вікно, і натомість показувати щось інформативне. Ось причина для "сценарію посередині"
hndcrftd

Ви можете навіть зробити це без iframe, прямо у вашому основному сценарії внутрішньої програми, але в цьому випадку ви чекаєте, коли RSS-канал повернеться перед обробкою та виведенням на сторінку. Я б зробив iFrame, щоб ваша сторінка завантажувалася асинхронно з RSS-каналом. Існує також варіант ajax, якщо ви хочете поїхати туди, щоб уникнути iframe. Просто цікаво - якою є ваша серверна платформа?
hndcrftd

2

Що стосується вашої другої вимоги - ви, можливо, зможете використати подію onerror, тобто. <img onerror="some javascript;"...

Оновлення:

Ви також можете спробувати пройти ітерацію document.imagesв будинку. Існує completeлогічна властивість, якою ви могли б скористатися. Я точно не знаю, чи це буде підходящим, але, можливо, варто це дослідити.


Цікаво, я навіть не підозрював, що сталася подія з помилкою. Мені довелося б переписати HTML (оскільки він надходить із зовнішнього джерела), але його вже дезінфікували за допомогою очищувача HTML, тому додавши, що це можливо як фільтр.
El Yobo

Чи не з’явиться жодне попередження про безпеку браузера до того, як JavaScript не зможе щось зробити?
MrWhite

0

Краще було б просто розміщувати вміст http на https


5
Якщо я не пояснив це у своєму питанні, вміст HTTP знаходиться на чужому сервері, а не на моєму. Зокрема, це посилання <img> у HTML, які я отримав із RSS-каналів. Зараз я наголосив на цьому у питанні.
El Yobo


0

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

Я вважаю, що ми ніколи не повинні завантажувати вміст http у https, а також не слід повертати сторінку https у версію http, щоб запобігти діалогу помилок.

єдиний спосіб забезпечити безпеку користувача - це використання https-версії всього вмісту, http://developers.facebook.com/blog/post/499/


3
Це можливо з facebook, але не для всього вмісту, і це питання стосувалося не facebook.
El Yobo,

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 див. 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;
}

-2

Просто: НЕ РОБІТЬ. Вміст Http на сторінці HTTPS за своєю суттю є небезпечним. Точка. Ось чому IE показує попередження. Позбавлення від попередження - це дурний підхід до фігня.

Натомість сторінка HTTPS повинна лише мати вміст HTTPS. Переконайтеся, що вміст також можна завантажити через HTTPS, і посилайтеся на нього через https, якщо сторінка завантажується через https. Для зовнішнього вмісту це означатиме завантаження та кешування елементів локально, щоб вони були доступні через https - звичайно. На жаль, навколо цього, на жаль.

Попередження є з поважної причини. Серйозно. Витратьте 5 хвилин на роздуми про те, як би ви могли зайняти показану на https сторінку зі спеціальним вмістом - ви будете здивовані.


3
Спокійно, я усвідомлюю, що для цього є вагома причина; Я думаю, що поведінка IE в цьому плані краща за FF. Я прагну не завантажувати вміст; Я просто хочу уникнути нав'язливого попередження про спливаюче вікно та показати щось інформативне замість вмісту.
El Yobo,

2
Шансів для цього немає - якщо ви не перепишете HTML на виході. Будь-яка спроба завантаження JavaScript після завантаження вже відображала діалогове вікно.
TomTom

Він просто запитував про зображення, і він не вимагає ніякого небезпечного тексту чи сценарію, тому ми можемо передати попередження, переписавши URL-адреси.
Джаяпал Чандран

1
Відповідь не змінюється. Зображення також можуть бути незахищеними. Це загальне - або воно надходить із захищеного джерела, або його може замінити людина в середині атаки.
TomTom

8
Проголосували проти, оскільки ця "відповідь" не дала відповіді про те, як досягти мети ОП.
MikeSchinkel

-3

Я усвідомлюю, що це стара тема, але один із варіантів - просто видалити частину http: із URL-адреси зображення, щоб " http: //some/image.jpg " стало "//some/image.jpg". Це також буде працювати з CDN


7
Це іноді спрацює, а іноді ні; це залежить від того, чи доступний вихідний вміст через HTTPS. Якщо ні, то просто зламається.
El Yobo

-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" /> 
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.