การจัดการกับเนื้อหา HTTP ในหน้า HTTPS


90

เรามีไซต์ที่เข้าถึงได้ทั้งหมดผ่าน HTTPS แต่บางครั้งก็แสดงเนื้อหาภายนอกซึ่งเป็น HTTP (รูปภาพจาก RSS feeds เป็นหลัก) ผู้ใช้ส่วนใหญ่ของเรายังติดอยู่บน IE6

ฉันอยากจะทำทั้งสองอย่างต่อไปนี้

  • ป้องกันข้อความเตือนของ IE เกี่ยวกับเนื้อหาที่ไม่ปลอดภัย (เพื่อที่ฉันจะได้แสดงสิ่งที่ล่วงล้ำน้อยลงเช่นโดยการแทนที่รูปภาพด้วยไอคอนเริ่มต้นตามด้านล่าง)
  • นำเสนอสิ่งที่เป็นประโยชน์ต่อผู้ใช้แทนรูปภาพที่พวกเขามองไม่เห็น หากมี JS บางตัวที่ฉันสามารถเรียกใช้เพื่อค้นหาว่าภาพใดที่ยังไม่ได้โหลดและแทนที่ด้วยภาพของเราซึ่งจะดีมาก

ฉันสงสัยว่าจุดมุ่งหมายแรกนั้นไม่สามารถทำได้ แต่อย่างที่สองอาจเพียงพอ

สถานการณ์ในกรณีที่เลวร้ายที่สุดคือฉันแยกวิเคราะห์ฟีด RSS เมื่อเรานำเข้าดึงรูปภาพนั้นเก็บไว้ในเครื่องเพื่อให้ผู้ใช้สามารถเข้าถึงได้ด้วยวิธีนั้น แต่ดูเหมือนว่าจะเจ็บปวดอย่างมากที่ได้รับประโยชน์เพียงเล็กน้อย

คำตอบ:


149

สถานการณ์เลวร้ายที่สุดของคุณไม่ได้เลวร้ายอย่างที่คุณคิด

คุณกำลังแยกวิเคราะห์ฟีด 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 จากสตริงการสืบค้นและตรวจสอบแฮช
  2. ดาวน์โหลดภาพจากเซิร์ฟเวอร์และพร็อกซีกลับไปที่เบราว์เซอร์
  3. หรือแคชอิมเมจบนดิสก์

โซลูชันนี้มีข้อดีบางประการ คุณไม่จำเป็นต้องดาวน์โหลดภาพในขณะที่สร้าง html คุณไม่จำเป็นต้องจัดเก็บภาพไว้ในเครื่อง นอกจากนี้คุณยังไร้สัญชาติ URL มีข้อมูลทั้งหมดที่จำเป็นในการแสดงภาพ

สุดท้ายพารามิเตอร์แฮชมีไว้เพื่อความปลอดภัย คุณต้องการให้ 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
ฟังดูดีมากและฉันคิดว่านี่คือสิ่งที่ฉันจะทำ เรากำลังใช้ PHP แต่การใช้งานก็เป็นเรื่องเล็กน้อยเช่นกัน ฉันจะใช้การแคชในฝั่งของเราด้วยเนื่องจากฉันไม่ต้องการดาวน์โหลดรูปภาพทุกครั้งที่มีคนร้องขอ (เพื่อประสิทธิภาพและการใช้งานแบนด์วิดธ์) คำแนะนำสำหรับแนวทางการรักษาความปลอดภัยนั้นฟังดูดี (แม้ว่าเราจะใช้รูปแบบการรักษาความปลอดภัยมาตรฐานของเราด้วยเช่นกัน) ขอบคุณสำหรับข้อเสนอแนะ
El Yobo

33
ข้อเสียอย่างเดียวของแนวทางนี้คือคุณกำหนดเส้นทางทรัพยากรภายนอกทั้งหมดผ่านระบบของคุณเอง ซึ่งไม่เพียง แต่เป็นหนี้สินเท่านั้น แต่ยังมีค่าใช้จ่ายค่อนข้างสูงอีกด้วย
Tim Molendijk

ฉันสอง @TimMolendijk เพิ่มว่าไม่เพียงเพิ่มค่าใช้จ่ายและการบำรุงรักษา แต่ยังเอาชนะ CDN ใด ๆ ที่ควรกำหนดเส้นทางไปยังเซิร์ฟเวอร์ที่อยู่ใกล้หรือปรับสมดุลให้กับเซิร์ฟเวอร์ที่ไม่ได้ใช้งาน
Levente Pánczél

2
โซลูชันสำหรับ NodeJS คืออะไร?
stkvtflw

1
+1 อีกอันสำหรับ @TimMolendijk แต่จะแก้อย่างไร ไซต์ที่ให้บริการผ่าน HTTPS ดูเหมือนจะเล่นได้ไม่ดีนักกับภาพที่ส่งผ่าน HTTP
FullStackForger

16

หากคุณกำลังมองหาวิธีแก้ปัญหาอย่างรวดเร็วในการโหลดภาพผ่าน HTTPS บริการ reverse proxy ฟรีที่https://images.weserv.nl/อาจทำให้คุณสนใจ มันคือสิ่งที่ฉันกำลังมองหา

หากคุณกำลังมองหาโซลูชันแบบชำระเงินฉันเคยใช้ Cloudinary.com มาก่อนซึ่งใช้งานได้ดี แต่แพงเกินไปสำหรับงานนี้ในความคิดของฉัน


จับอะไร? ใช้งานได้ดี
Jack

5
@JackNicholson ฉันใช้มันค่อนข้างหนักมา 2 ปีแล้ว ใช้งานได้ดี! ความรุ่งโรจน์ให้กับผู้พัฒนาทั้งสอง
โมฆะ

ฉันมีลิงก์ (วิดีโอหรือไซต์) ที่ขึ้นต้นด้วย Http และฉันไม่สามารถแสดงลิงก์เหล่านี้ใน Iframe บนไซต์ https ของเราได้ เนื่องจากเป็นลิงค์ที่ไม่ปลอดภัยจึงใช้งานไม่ได้ สำหรับรูปภาพฉันได้แก้ไขปัญหาโดยใช้แคชรูปภาพแล้ว ใครมีความคิด
cs1985

@ int14 คุณจะต้องตั้งค่า reverse proxy สำหรับไซต์ http คุณสามารถทำได้ด้วย AWS API Gateway
nullable

3

ฉันไม่รู้ว่าสิ่งนี้จะเข้ากับสิ่งที่คุณกำลังทำอยู่หรือไม่ แต่ในการแก้ไขอย่างรวดเร็วฉันจะ "รวม" เนื้อหา http ไว้ในสคริปต์ https ตัวอย่างเช่นบนเพจของคุณที่แสดงผ่าน https ฉันจะแนะนำ iframe ที่จะแทนที่ฟีด rss ของคุณและใน src attr ของ iframe จะใส่ url ของสคริปต์บนเซิร์ฟเวอร์ของคุณที่จับฟีดและแสดงผล html สคริปต์กำลังอ่านฟีดผ่าน http และส่งออกผ่าน https (ดังนั้น "การตัด")

เพียงแค่ความคิด


สำหรับฉันแล้วดูเหมือนว่าสิ่งนี้จะทำให้ฉันตกอยู่ในสถานการณ์เดียวกับที่ฉันอยู่ในตอนนี้ ฉันแสดงเนื้อหาในหน้า HTTPS แล้วปัญหาคือมีแท็ก <img> ในเนื้อหาที่มีค่า http: // src ซึ่งไม่ปรากฏและทำให้เกิดข้อความที่น่ารำคาญ
El Yobo

ใช่ถ้าคุณเก็บลิงก์ต้นฉบับไปยังรูปภาพไม่มีวิธีใดที่จะหลีกเลี่ยงปัญหานี้ได้ สคริปต์ Wrapper จะต้องสแกนเนื้อหาฟีด rss สำหรับรูปภาพและลบออก ดังที่คุณกล่าวไว้ในความคิดเห็นอื่นคุณไม่ต้องการโหลดเนื้อหาที่ทำให้เกิดป๊อปอัปและแสดงข้อมูลบางอย่างแทน นั่นเป็นเหตุผลสำหรับ "สคริปต์ตรงกลาง"
hndcrftd

คุณสามารถทำได้โดยไม่ต้องใช้ iframe ในสคริปต์แบ็กเอนด์หลักของคุณ แต่ในกรณีนี้คุณกำลังรอให้ฟีด rss กลับมาก่อนที่จะประมวลผลและแสดงผลบนเพจ ฉันจะทำ iFrame เพื่อให้หน้าของคุณโหลดแบบอะซิงโครนัสกับฟีด rss นอกจากนี้ยังมีตัวเลือก ajax หากคุณต้องการไปที่นั่นเพื่อหลีกเลี่ยง iframe แค่อยากรู้ - แพลตฟอร์มแบ็กเอนด์ของคุณคืออะไร?
hndcrftd

2

เกี่ยวกับความต้องการที่สองของคุณ - คุณอาจสามารถใช้เหตุการณ์ onerror ได้เช่น <img onerror="some javascript;"...

อัปเดต:

คุณยังสามารถลองทำซ้ำdocument.imagesในโดม มีcompleteคุณสมบัติบูลีนที่คุณอาจสามารถใช้ได้ ฉันไม่รู้แน่ชัดว่าสิ่งนี้จะเหมาะหรือไม่ แต่ก็ควรค่าแก่การตรวจสอบ


ที่น่าสนใจผมไม่ได้รู้ว่ามีเป็นเหตุการณ์ onerror ฉันต้องเขียน HTML ใหม่ (เนื่องจากมาจากแหล่งภายนอก) แต่ได้รับการทำความสะอาดด้วยตัวกรอง HTML แล้วดังนั้นการเพิ่มเป็นตัวกรองอาจเป็นไปได้
El Yobo

คำเตือนความปลอดภัยของเบราว์เซอร์จะไม่เกิดขึ้นก่อนที่ JavaScript จะมีโอกาสทำอะไร?
MrWhite

1

คำตอบที่ได้รับการยอมรับช่วยให้ฉันอัปเดตสิ่งนี้เป็น 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;
}

1

บางครั้งเช่นเดียวกับในแอพ Facebook เราไม่สามารถมีเนื้อหาที่ไม่ปลอดภัยในหน้าที่ปลอดภัยได้ นอกจากนี้เราไม่สามารถสร้างเนื้อหาเหล่านั้นในท้องถิ่นได้ ตัวอย่างเช่นแอปที่จะโหลดใน iFrame ไม่ใช่เนื้อหาธรรมดาและเราไม่สามารถทำให้มันอยู่ในเครื่องได้

ฉันคิดว่าเราไม่ควรโหลดเนื้อหา http ใน https และเราไม่ควรสำรองหน้า https เป็นเวอร์ชัน http เพื่อป้องกันการโต้ตอบข้อผิดพลาด

วิธีเดียวที่จะรับประกันความปลอดภัยของผู้ใช้คือใช้เวอร์ชัน https ของเนื้อหาทั้งหมดhttp://web.archive.org/web/20120502131549/http://developers.facebook.com/blog/post/499/


3
อาจเป็นไปได้กับ facebook แต่ไม่ใช่สำหรับเนื้อหาทั้งหมดและคำถามนี้ไม่เกี่ยวกับ facebook
El Yobo

0

จะเป็นการดีที่สุดหากมีเนื้อหา http บน https


5
หากฉันไม่ได้อธิบายให้ชัดเจนในคำถามของฉันเนื้อหา HTTP อยู่บนเซิร์ฟเวอร์ของคนอื่นไม่ใช่ของฉัน โดยเฉพาะอย่างยิ่งมันเป็นลิงก์ <img> ใน HTML ที่ฉันดึงมาจาก RSS feeds ฉันได้เน้นย้ำในคำถามนี้แล้ว
El Yobo

ตกลงwebproworld.com/webmaster-forum/threads/…จะช่วยได้ไหม
Daniel

-1

ง่ายๆ: อย่าทำ เนื้อหา HTTP ภายในเพจ HTTPS นั้นไม่ปลอดภัยโดยเนื้อแท้ จุด. นี่คือสาเหตุที่ IE แสดงคำเตือน การกำจัดคำเตือนเป็นวิธีการที่โง่เขลา

แต่หน้า HTTPS ควรมีเฉพาะเนื้อหา HTTPS ตรวจสอบให้แน่ใจว่าสามารถโหลดเนื้อหาผ่าน HTTPS ได้เช่นกันและอ้างอิงผ่าน https หากโหลดหน้าเว็บผ่าน https สำหรับเนื้อหาภายนอกจะหมายถึงการโหลดและแคชองค์ประกอบในเครื่องเพื่อให้พร้อมใช้งานผ่าน https - แน่นอน ไม่มีทางรอบนั้นเศร้า

คำเตือนมีเหตุผลที่ดี อย่างจริงจัง. ใช้เวลา 5 นาทีในการคิดว่าคุณจะเข้าครอบครองหน้าที่แสดง https ด้วยเนื้อหาที่กำหนดเองได้อย่างไร - คุณจะต้องประหลาดใจ


3
ง่ายมากฉันรู้ว่ามันมีเหตุผลที่ดี ผมคิดว่าพฤติกรรมของ IE ดีกว่า FF ในเรื่องนี้ สิ่งที่ฉันตั้งเป้าไว้คือไม่โหลดเนื้อหา ฉันแค่ต้องการหลีกเลี่ยงคำเตือนสไตล์ป๊อปอัปที่ล่วงล้ำและเพื่อแสดงข้อมูลที่เป็นประโยชน์แทนเนื้อหา
El Yobo

2
ไม่มีโอกาสสำหรับสิ่งนั้นเว้นแต่คุณจะเขียน HTML ใหม่ในขณะที่ออก ความพยายามในการโหลดโพสต์จาวาสคริปต์ใด ๆ แสดงกล่องโต้ตอบ
TomTom

เขาแค่ถามเกี่ยวกับรูปภาพและเขาไม่ได้ขอข้อความหรือสคริปต์ที่ไม่ปลอดภัยดังนั้นเราจึงสามารถส่งคำเตือนโดยเขียน URL ใหม่
Jayapal Chandran

1
ไม่มีการเปลี่ยนแปลงคำตอบ รูปภาพอาจไม่ปลอดภัย เป็นเรื่องทั่วไป - ไม่ว่าจะมาจากแหล่งที่ปลอดภัยหรืออาจถูกแทนที่ด้วยผู้ชายในการโจมตีกลาง
TomTom

8
โหวตลดลงเพราะ"คำตอบ"นี้ไม่ได้ตอบโจทย์ว่าจะบรรลุเป้าหมายของ OP ได้อย่างไร
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" /> 
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.