Berurusan dengan konten HTTP di halaman HTTPS


90

Kami memiliki situs yang sepenuhnya diakses melalui HTTPS, tetapi terkadang menampilkan konten eksternal yaitu HTTP (gambar dari RSS feed, terutama). Sebagian besar pengguna kami juga terjebak di IE6.

Idealnya, saya ingin melakukan kedua hal berikut

  • Cegah pesan peringatan IE tentang konten tidak aman (sehingga saya dapat menampilkan yang tidak terlalu mengganggu, misalnya dengan mengganti gambar dengan ikon default seperti di bawah)
  • Menampilkan sesuatu yang berguna bagi pengguna sebagai ganti gambar yang tidak dapat mereka lihat; jika ada beberapa JS, saya bisa lari untuk mencari tahu gambar mana yang belum dimuat dan menggantinya dengan gambar milik kami, itu akan bagus.

Saya menduga bahwa tujuan pertama sama sekali tidak mungkin, tetapi tujuan kedua mungkin cukup.

Skenario kasus terburuk adalah saya mengurai RSS feed ketika kita mengimpornya, mengambil gambar menyimpannya secara lokal sehingga pengguna dapat mengaksesnya dengan cara itu, tetapi sepertinya sangat merepotkan untuk keuntungan yang cukup kecil.

Jawaban:


148

Skenario terburuk Anda tidak seburuk yang Anda pikirkan.

Anda sudah mengurai umpan RSS, jadi Anda sudah memiliki URL gambarnya. Katakanlah Anda memiliki URL gambar seperti http://otherdomain.com/someimage.jpg. Anda menulis ulang URL ini sebagai https://mydomain.com/imageserver?url=http://otherdomain.com/someimage.jpg&hash=abcdeafad. Dengan cara ini, browser selalu membuat permintaan melalui https, jadi Anda bisa mengatasi masalah tersebut.

Bagian selanjutnya - buat halaman proxy atau servlet yang melakukan hal berikut -

  1. Baca parameter url dari string kueri, dan verifikasi hash
  2. Unduh gambar dari server, dan proksi kembali ke browser
  3. Secara opsional, buat cache gambar di disk

Solusi ini memiliki beberapa keunggulan. Anda tidak perlu mengunduh gambar pada saat membuat html. Anda tidak harus menyimpan gambar secara lokal. Juga, Anda tidak memiliki kewarganegaraan; url berisi semua informasi yang diperlukan untuk menyajikan gambar.

Terakhir, parameter hash adalah untuk keamanan; Anda hanya ingin servlet Anda menampilkan gambar untuk url yang telah Anda buat. Jadi, saat Anda membuat url, hitung md5(image_url + secret_key)dan tambahkan sebagai parameter hash. Sebelum Anda melayani permintaan, hitung ulang hash dan bandingkan dengan apa yang diteruskan kepada Anda. Karena secret_key hanya diketahui oleh Anda, tidak ada orang lain yang dapat membuat url valid.

Jika Anda mengembangkan aplikasi di java, Servlet hanyalah beberapa baris kode. Anda harus dapat memindahkan kode di bawah ini ke teknologi back-end lainnya.

/*
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
Sangat sehat, dan saya pikir inilah yang akan saya gunakan. Kami menggunakan PHP, tetapi implementasinya juga akan sepele. Saya juga akan menerapkan caching di pihak kami, karena saya tidak ingin mengunduh gambar setiap kali seseorang memintanya (untuk kinerja dan penggunaan bandwith). Saran untuk pendekatan keamanan bagus (meskipun kami juga akan menerapkan model keamanan standar kami seperti yang disebutkan di atas). Terima kasih atas saran Anda.
El Yobo

33
Satu-satunya kelemahan serius dari pendekatan ini adalah Anda merutekan semua sumber daya eksternal melalui sistem Anda sendiri. Yang tidak hanya menjadi kewajiban, tetapi juga bisa menjadi agak mahal.
Tim Molendijk

Saya kedua @TimMolendijk, menambahkan bahwa itu tidak hanya menambah biaya dan pemeliharaan tetapi juga mengalahkan semua CDN yang seharusnya diarahkan ke server dekat atau menyeimbangkan ke yang tidak aktif.
Levente Pánczél

2
Apa solusi untuk NodeJS?
stkvtflw

1
+1 lagi untuk @TimMolendijk tetapi apa solusinya? situs yang disajikan melalui HTTPS tampaknya tidak berfungsi dengan baik dengan gambar yang dikirim melalui HTTP
FullStackForger

16

Jika Anda mencari solusi cepat untuk memuat gambar melalui HTTPS maka layanan proxy terbalik gratis di https://images.weserv.nl/ mungkin menarik bagi Anda. Itu persis seperti yang saya cari.

Jika Anda mencari solusi berbayar, saya sebelumnya telah menggunakan Cloudinary.com yang juga berfungsi dengan baik tetapi terlalu mahal hanya untuk tugas ini, menurut saya.


Apa tangkapannya? Bekerja dengan baik
Jack

5
@JackNicholson Saya telah menggunakannya di bawah beban yang relatif berat selama 2 tahun. Bekerja dengan baik! Kudos to the two devs.
batal

Saya memiliki beberapa tautan (video atau situs) yang dimulai dengan Http dan saya tidak dapat menampilkannya dalam Iframe di situs https kami. Karena ini adalah tautan yang tidak aman, ini tidak berfungsi. untuk gambar, saya telah menyelesaikan masalah menggunakan cache gambar. Ada yang punya ide
int14

@ int14 Anda perlu menyiapkan proxy balik untuk situs http, Anda dapat melakukannya dengan sesuatu seperti AWS API Gateway.
batal

3

Saya tidak tahu apakah ini cocok dengan apa yang Anda lakukan, tetapi sebagai perbaikan cepat saya akan "membungkus" konten http ke dalam skrip https. Misalnya, di halaman Anda yang disajikan melalui https, saya akan memperkenalkan iframe yang akan menggantikan feed rss Anda dan di src attr dari iframe letakkan url skrip di server Anda yang menangkap feed dan mengeluarkan html. skrip membaca umpan melalui http dan mengeluarkannya melalui https (dengan demikian "membungkus")

Hanya pemikiran saja


Tampaknya bagi saya bahwa ini akan membuat saya berada dalam situasi yang sama seperti saya sekarang; Saya sudah menampilkan konten di halaman HTTPS - masalahnya adalah ada tag <img> di konten dengan nilai http: // src - yang tidak ditampilkan dan menyebabkan pesan yang mengganggu terjadi.
El Yobo

ya, jika Anda menyimpan tautan asli ke gambar, tidak ada cara untuk menghindari masalah tersebut. Skrip pembungkus harus memindai konten rss feed untuk mencari gambar dan menghapusnya. Seperti yang Anda sebutkan di komentar lain - Anda tidak ingin memuat konten yang menyebabkan munculan dan menampilkan sesuatu yang informatif. Itulah alasan untuk "skrip di tengah"
hndcrftd

Anda bahkan dapat melakukan ini tanpa iframe, tepat di skrip backend utama Anda, tetapi dalam hal ini Anda menunggu umpan rss kembali sebelum diproses dan dikeluarkan pada halaman. Saya akan melakukan iFrame sehingga halaman Anda dimuat secara asinkron dengan rss feed. Ada juga opsi ajax jika Anda ingin pergi ke sana untuk menghindari iframe. Hanya ingin tahu - apa platform backend Anda?
hndcrftd

2

Mengenai persyaratan kedua Anda - Anda mungkin dapat memanfaatkan acara onerror, yaitu. <img onerror="some javascript;"...

Memperbarui:

Anda juga dapat mencoba melakukan iterasi melalui document.imagesdom. Ada completeproperti boolean yang mungkin bisa Anda gunakan. Saya tidak tahu pasti apakah ini cocok, tetapi mungkin perlu diselidiki.


Menarik, aku bahkan tidak tahu ada adalah suatu peristiwa OnError. Saya harus menulis ulang HTML (karena berasal dari sumber eksternal), tetapi sudah dibersihkan dengan pemurni HTML, jadi menambahkannya sebagai filter dimungkinkan.
El Yobo

Tidakkah peringatan keamanan browser akan muncul sebelum JavaScript sempat melakukan sesuatu?
MrWhite

0

Akan lebih baik jika memiliki konten http di https


5
Jika saya tidak memperjelas ini dalam pertanyaan saya, konten HTTP ada di server orang lain bukan milik saya. Secara khusus, ini adalah tautan <img> dalam HTML yang saya ambil dari umpan RSS. Saya telah menekankan hal ini dalam pertanyaan sekarang.
El Yobo

Oh oke, apakah webproworld.com/webmaster-forum/threads/… membantu sama sekali?
Daniel

0

Terkadang seperti di aplikasi facebook kita tidak dapat memiliki konten yang tidak aman di halaman aman. juga kita tidak bisa membuat lokal isinya. misalnya aplikasi yang akan dimuat di iFrame bukanlah konten sederhana dan kami tidak dapat menjadikannya lokal.

Saya pikir kita tidak boleh memuat konten http di https, juga kita tidak boleh mengembalikan halaman https ke versi http untuk mencegah dialog kesalahan.

satu-satunya cara yang akan memastikan keamanan pengguna adalah dengan menggunakan versi https dari semua konten, http://developers.facebook.com/blog/post/499/


3
Itu mungkin dilakukan dengan facebook, tapi tidak untuk semua konten dan pertanyaan ini bukan tentang facebook.
El Yobo

0

Jawaban yang diterima membantu saya memperbarui ini baik ke PHP maupun CORS, jadi saya pikir saya akan menyertakan solusi untuk orang lain:

PHP / HTML murni:

<?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 lihat http://stackoverflow.com/questions/8719276/cors-with-php-headers?noredirect=1&lq=1 untuk lebih lanjut tentang 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

Sederhananya: JANGAN LAKUKAN. Konten Http dalam halaman HTTPS secara inheren tidak aman. Titik. Inilah mengapa IE menampilkan peringatan. Menyingkirkan peringatan itu adalah pendekatan omong kosong yang bodoh.

Sebagai gantinya, halaman HTTPS seharusnya hanya memiliki konten HTTPS. Pastikan konten juga dapat dimuat melalui HTTPS, dan referensikan melalui https jika halaman dimuat melalui https. Untuk konten eksternal ini berarti memuat dan menyimpan elemen secara lokal sehingga tersedia melalui https - tentu. Tidak ada jalan lain, sayangnya.

Peringatan itu ada untuk alasan yang bagus. Sungguh. Luangkan 5 menit untuk memikirkan bagaimana Anda dapat mengambil alih https yang ditampilkan halaman dengan konten kustom - Anda akan terkejut.


3
Mudah saja, saya sadar ada alasan bagus untuk itu; Saya pikir perilaku IE lebih baik daripada FF dalam hal ini. Apa yang saya tuju bukanlah memuat konten; Saya hanya ingin menghindari peringatan gaya popup yang mengganggu dan menampilkan sesuatu yang informatif sebagai pengganti konten.
El Yobo

2
Tidak ada kesempatan untuk itu - kecuali Anda menulis ulang HTML di jalan keluar. Setiap upaya pemuatan posting javascript telah menampilkan dialog.
TomTom

Dia hanya bertanya tentang gambar dan dia tidak meminta teks atau skrip yang tidak aman sehingga kami dapat melewati peringatan dengan menulis ulang url.
Jayapal Chandran

1
Tidak ada perubahan pada jawabannya. Gambar juga bisa jadi tidak aman. Ini adalah hal yang umum - baik itu datang dari sumber yang aman, atau dapat digantikan oleh orang di tengah serangan.
TomTom

8
Tidak disukai karena "jawaban" ini tidak menjawab bagaimana mencapai tujuan OP.
MikeSchinkel

-3

Saya menyadari bahwa ini adalah utas lama tetapi salah satu pilihan adalah menghapus http: bagian dari URL gambar sehingga ' http: //some/image.jpg ' menjadi '//some/image.jpg'. Ini juga akan bekerja dengan CDN


7
Ini terkadang berhasil dan terkadang tidak; itu tergantung apakah konten upstream tersedia melalui HTTPS. Jika tidak, itu hanya akan rusak.
El Yobo

-3

Cara terbaik bekerja untuk saya

<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" /> 
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.