Xử lý nội dung HTTP trong các trang HTTPS


89

Chúng tôi có một trang web được truy cập hoàn toàn qua HTTPS, nhưng đôi khi hiển thị nội dung bên ngoài là HTTP (chủ yếu là hình ảnh từ nguồn cấp dữ liệu RSS). Phần lớn người dùng của chúng tôi cũng bị mắc kẹt trên IE6.

Lý tưởng nhất là tôi muốn làm cả hai điều sau

  • Ngăn thông báo cảnh báo của IE về nội dung không an toàn (để tôi có thể hiển thị nội dung ít xâm phạm hơn, ví dụ: bằng cách thay thế các hình ảnh bằng biểu tượng mặc định như bên dưới)
  • Trình bày thứ gì đó hữu ích cho người dùng thay cho những hình ảnh mà họ không thể nhìn thấy; nếu có một số JS tôi có thể chạy để tìm ra những hình ảnh nào chưa được tải và thay thế chúng bằng một hình ảnh của chúng tôi, điều đó sẽ rất tuyệt.

Tôi nghi ngờ rằng mục tiêu đầu tiên đơn giản là không thể thực hiện được, nhưng mục tiêu thứ hai có thể đủ.

Một trường hợp xấu nhất là tôi phân tích cú pháp các nguồn cấp dữ liệu RSS khi chúng tôi nhập chúng, lấy các hình ảnh lưu trữ cục bộ để người dùng có thể truy cập theo cách đó, nhưng có vẻ như rất khó khăn khi thu được rất ít.

Câu trả lời:


147

Tình huống xấu nhất của bạn không tệ như bạn nghĩ.

Bạn đã phân tích cú pháp nguồn cấp dữ liệu RSS, vì vậy bạn đã có các URL hình ảnh. Giả sử bạn có một URL hình ảnh như thế nào http://otherdomain.com/someimage.jpg. Bạn viết lại URL này thànhhttps://mydomain.com/imageserver?url=http://otherdomain.com/someimage.jpg&hash=abcdeafad . Bằng cách này, trình duyệt luôn đưa ra yêu cầu qua https, vì vậy bạn sẽ thoát khỏi sự cố.

Phần tiếp theo - tạo một trang proxy hoặc servlet thực hiện những việc sau -

  1. Đọc tham số url từ chuỗi truy vấn và xác minh hàm băm
  2. Tải xuống hình ảnh từ máy chủ và ủy quyền nó trở lại trình duyệt
  3. Tùy chọn, lưu hình ảnh vào bộ nhớ cache trên đĩa

Giải pháp này có một số ưu điểm. Bạn không phải tải xuống hình ảnh tại thời điểm tạo html. Bạn không cần phải lưu trữ hình ảnh cục bộ. Ngoài ra, bạn không có quốc tịch; url chứa tất cả thông tin cần thiết để cung cấp hình ảnh.

Cuối cùng, tham số băm là để bảo mật; bạn chỉ muốn servlet của mình cung cấp hình ảnh cho các url mà bạn đã xây dựng. Vì vậy, khi bạn tạo url, hãy tính toán md5(image_url + secret_key)và nối nó làm tham số băm. Trước khi bạn gửi yêu cầu, hãy tính toán lại hàm băm và so sánh nó với những gì đã được chuyển cho bạn. Vì khóa bí mật chỉ có bạn biết nên không ai khác có thể tạo các url hợp lệ.

Nếu bạn đang phát triển trong java, Servlet chỉ là một vài dòng mã. Bạn sẽ có thể chuyển mã bên dưới trên bất kỳ công nghệ back-end nào khác.

/*
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
Rất âm thanh, và tôi nghĩ đây là những gì tôi sẽ sử dụng. Chúng tôi đang sử dụng PHP, nhưng việc triển khai cũng sẽ rất nhỏ. Tôi cũng sẽ triển khai bộ nhớ đệm ở phía chúng tôi, vì tôi không muốn tải hình ảnh xuống mỗi khi ai đó yêu cầu nó (để sử dụng hiệu suất và băng thông). Các đề xuất cho phương pháp bảo mật là đúng đắn (mặc dù chúng tôi cũng sẽ áp dụng mô hình bảo mật tiêu chuẩn của chúng tôi cũng như mô hình ở trên). Cảm ơn đề nghị của bạn.
El Yobo

32
Nhược điểm nghiêm trọng duy nhất của phương pháp này là bạn đang định tuyến tất cả các tài nguyên bên ngoài thông qua hệ thống của riêng bạn. Điều này không chỉ là một khoản nợ, mà còn có thể khá tốn kém.
Tim Molendijk

Tôi thứ hai là @TimMolendijk, nói thêm rằng nó không chỉ thêm chi phí và bảo trì mà còn đánh bại bất kỳ CDN nào được cho là định tuyến đến các máy chủ gần hoặc cân bằng với các máy chủ không hoạt động.
Levente Pánczél

2
Giải pháp cho NodeJS là gì?
stkvtflw

1
+1 khác cho @TimMolendijk nhưng giải pháp sau đó sẽ là gì? trang web được phân phối qua HTTPS dường như không hoạt động tốt với hình ảnh được phân phối qua HTTP
FullStackForger

15

Nếu bạn đang tìm kiếm một giải pháp nhanh chóng để tải hình ảnh qua HTTPS thì hãy sử dụng dịch vụ proxy ngược miễn phí tại https://images.weserv.nl/ có thể khiến bạn quan tâm. Đó chính xác là những gì tôi đang tìm kiếm.

Nếu bạn đang tìm kiếm một giải pháp trả phí, trước đây tôi đã sử dụng Cloudinary.com, công cụ này cũng hoạt động tốt nhưng quá đắt nếu chỉ áp dụng cho nhiệm vụ này, theo ý kiến ​​của tôi.


Bắt được là gì? Hoạt động tuyệt vời
Jack

5
@JackNicholson Tôi đã sử dụng nó dưới tải tương đối nặng trong 2 năm. Hoạt động tuyệt vời! Kudo cho hai nhà phát triển.
nullable

Tôi có một số liên kết (video hoặc trang web) bắt đầu bằng Http và tôi không thể hiển thị chúng trong Iframe trên trang https của chúng tôi. Vì đây là liên kết không an toàn nên nó không hoạt động. cho một hình ảnh, tôi đã giải quyết vấn đề bằng cách sử dụng bộ nhớ cache hình ảnh. Bất cứ ai có bất kỳ ý tưởng nào
int14

@ int14 Bạn sẽ cần thiết lập proxy ngược cho trang web http, bạn có thể thực hiện việc này với một cái gì đó như AWS API Gateway.
nullable

3

Tôi không biết liệu điều này có phù hợp với những gì bạn đang làm hay không, nhưng để sửa lỗi nhanh chóng, tôi sẽ "bọc" nội dung http vào một tập lệnh https. Ví dụ: trên trang của bạn được phân phát thông qua https, tôi sẽ giới thiệu một iframe sẽ thay thế nguồn cấp dữ liệu rss của bạn và trong src attr của iframe đặt một url của một tập lệnh trên máy chủ của bạn để nắm bắt nguồn cấp dữ liệu và xuất ra html. tập lệnh đang đọc nguồn cấp dữ liệu qua http và xuất nó qua https (do đó "gói")

Chỉ là một suy nghĩ


Đối với tôi, dường như điều này sẽ khiến tôi rơi vào tình trạng giống như tôi bây giờ; Tôi đã hiển thị nội dung trong trang HTTPS - vấn đề là có các thẻ <img> trong nội dung với các giá trị http: // src - không hiển thị và gây ra thông báo khó chịu.
El Yobo

Vâng, vâng, nếu bạn giữ các liên kết ban đầu đến hình ảnh, không có cách nào tránh được vấn đề. Tập lệnh trình bao bọc sẽ phải quét nội dung nguồn cấp dữ liệu rss để tìm hình ảnh và xóa chúng. Như bạn đã đề cập trong một nhận xét khác - bạn không muốn tải nội dung gây ra cửa sổ bật lên và thay vào đó hiển thị một cái gì đó nhiều thông tin. Đó là lý do cho "kịch bản ở giữa"
hndcrftd

Bạn thậm chí có thể làm điều này mà không cần iframe, ngay trong tập lệnh phụ trợ chính của bạn, nhưng trong trường hợp này, bạn đang đợi nguồn cấp dữ liệu rss quay lại trước khi được xử lý và xuất trên một trang. Tôi sẽ làm một iFrame để trang của bạn tải không đồng bộ với nguồn cấp dữ liệu rss. Ngoài ra còn có tùy chọn ajax nếu bạn muốn đến đó để tránh iframe. Chỉ tò mò - nền tảng phụ trợ của bạn là gì?
hndcrftd

2

Về yêu cầu thứ hai của bạn - bạn có thể sử dụng sự kiện onerror, tức là. <img onerror="some javascript;"...

Cập nhật:

Bạn cũng có thể thử lặp lại document.imagestrong dom. Có một thuộc tính completeboolean mà bạn có thể sử dụng. Tôi không biết chắc liệu điều này có phù hợp hay không, nhưng có thể đáng để điều tra.


Thú vị, tôi thậm chí không biết có một sự kiện onerror. Tôi sẽ phải viết lại HTML (vì nó đến từ một nguồn bên ngoài), nhưng nó đã được làm sạch bằng trình lọc HTML, vì vậy có thể thêm nó làm bộ lọc.
El Yobo

Sẽ không có bất kỳ cảnh báo bảo mật trình duyệt nào xảy ra trước khi JavaScript có cơ hội thực hiện bất cứ điều gì?
MrWhite

0

Tốt nhất là chỉ có nội dung http trên https


5
Nếu tôi không làm rõ điều này trong câu hỏi của mình, thì nội dung HTTP trên máy chủ của người khác không phải của tôi. Cụ thể, đó là các liên kết <img> trong HTML mà tôi đã lấy từ nguồn cấp dữ liệu RSS. Tôi đã nhấn mạnh điều này trong câu hỏi bây giờ.
El Yobo

Ồ được rồi, webproworld.com/webmaster-forum/threads/… có giúp được gì không?
Daniel

0

Đôi khi giống như trong các ứng dụng facebook, chúng ta không thể có nội dung không an toàn trong trang an toàn. chúng tôi cũng không thể làm cho các nội dung đó cục bộ. ví dụ một ứng dụng sẽ tải trong iFrame không phải là một nội dung đơn giản và chúng tôi không thể làm cho nó cục bộ.

Tôi nghĩ chúng ta không bao giờ nên tải nội dung http bằng https, cũng không nên dự phòng trang https thành phiên bản http để tránh hộp thoại lỗi.

cách duy nhất sẽ đảm bảo tính bảo mật của người dùng là sử dụng phiên bản https của tất cả nội dung, http://developers.facebook.com/blog/post/499/


3
Điều đó có thể xảy ra với facebook, nhưng không phải với tất cả nội dung và câu hỏi này không phải về facebook.
El Yobo

0

Câu trả lời được chấp nhận đã giúp tôi cập nhật điều này lên cả PHP cũng như CORS, vì vậy tôi nghĩ tôi sẽ bao gồm giải pháp cho những người khác:

PHP / HTML thuần túy:

<?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 xem http://stackoverflow.com/questions/8719276/cors-with-php-headers?noredirect=1&lq=1 để biết thêm về 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

Đơn giản là: KHÔNG LÀM ĐƯỢC. Http Nội dung trong trang HTTPS vốn không an toàn. Điểm. Đây là lý do tại sao IE hiển thị cảnh báo. Loại bỏ cảnh báo là một cách tiếp cận ngu ngốc của hogwash.

Thay vào đó, trang HTTPS chỉ nên có nội dung HTTPS. Đảm bảo rằng nội dung cũng có thể được tải qua HTTPS và tham chiếu qua https nếu trang được tải qua https. Đối với nội dung bên ngoài, điều này có nghĩa là tải và lưu trữ cục bộ các phần tử để chúng có sẵn qua https - chắc chắn. Thật đáng buồn.

Cảnh báo ở đó là có lý do chính đáng. Nghiêm túc. Dành 5 phút để suy nghĩ về cách bạn có thể tiếp quản một trang hiển thị https với nội dung tùy chỉnh - bạn sẽ ngạc nhiên.


3
Dễ dàng ở đó, tôi biết rằng có một lý do chính đáng cho nó; Tôi nghĩ rằng hành vi của IE tốt hơn FF về mặt này. Điều tôi hướng tới không phải là tải nội dung; Tôi chỉ muốn tránh cảnh báo kiểu cửa sổ bật lên xâm nhập và hiển thị một cái gì đó nhiều thông tin thay cho nội dung.
El Yobo

2
Không có cơ hội cho điều đó - trừ khi bạn viết lại HTML trên đường đi. Bất kỳ nỗ lực tải bài viết javascript nào đã hiển thị hộp thoại.
TomTom

Anh ấy chỉ hỏi về hình ảnh và anh ấy không yêu cầu bất kỳ văn bản hoặc tập lệnh không an toàn nào để chúng tôi có thể vượt qua cảnh báo bằng cách viết lại các url.
Jayapal Chandran

1
Không thay đổi câu trả lời. Hình ảnh cũng có thể không an toàn. Đó là một điều chung chung - hoặc nó đến từ nguồn được bảo mật, orit có thể được thay thế bởi một người đàn ông trong cuộc tấn công giữa.
TomTom

8
Bị phản đối vì "câu trả lời" này không giải đáp được cách đạt được mục tiêu của OP.
MikeSchinkel

-3

Tôi nhận ra rằng đây là một chủ đề cũ nhưng một tùy chọn chỉ là xóa phần http: khỏi URL hình ảnh để ' http: //some/image.jpg ' trở thành '//some/image.jpg'. Điều này cũng sẽ hoạt động với CDN


7
Điều này đôi khi sẽ hiệu quả và đôi khi không; nó phụ thuộc vào nội dung ngược dòng có khả dụng qua HTTPS hay không. Nếu không, nó sẽ chỉ bị vỡ.
El Yobo

-3

Cách tốt nhất cho tôi

<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" /> 
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.