VẤN ĐỀ LỘ THÔNG TIN TỪ ẢNH TRÊN CÁC TRANG BÁO
Nguy cơ lộ các thông tin nhạy cảm từ những bức ảnh được đăng trên những trang báo nhiều người đọc tại Việt Nam là vấn đề chưa được quan tâm đúng cách.
Hình ảnh là một phần không thể thiếu trong các bài báo để thu hút người đọc, cũng như cung cấp thêm thông tin trực quan về vấn đề được nêu. Thứ chúng ta nhìn thấy chỉ là vẻ ngoài của bức ảnh. Còn phần “nội tâm” chẳng mấy ai để ý tới, lại chứa rất nhiều thông tin quan trọng về bức ảnh đó. Tôi đang nói tới Metadata.
Metadata là gì?
Siêu dữ liệu hình ảnh (photo metadata) là một tập hợp thông tin về các thông số kĩ thuật, xử lí hậu kì cũng như thông tin về các quyền và quản lí hình ảnh. Trên các thiết bị chụp ảnh hiện đại, khi một tấm ảnh được chụp, các dữ liệu như thông số kỹ thuật, tên thiết bị, địa điểm chụp… và rất nhiều thông tin khác sẽ được lưu ngầm cùng với bức ảnh. Các thông tin này tuy rất đa dạng, lại thường không được người dùng phổ thông để ý tới.
Khi ta up một tấm ảnh lên trên một ứng dụng web, nếu trang web đó không xử lý metadata, hoặc chính ta không xử lý nó, rất có thể các dữ liệu này sẽ tồn tại một cách hớ hênh trên các trang web, các ứng dụng. Các dữ liệu này rất có thể bị ai đó khai thác được khi tải ảnh về.
Cơ duyên với các trang báo
Trong thời gian theo học khóa xóa mù Web Penetration Testing tại tổ chức Cookie Arena, thầy tôi hay cho anh em rất nhiều những gợi ý thú vị. Một hôm thầy tôi đang dạy về exiftool (là một công cụ để xem metadata ảnh), thầy nói vu vơ : “Anh em thử lấy ảnh báo mạng về xem nó còn metadata không 🐧”. Tôi, một thằng mới bước chân vào con đường tăm tối, cũng tò mò ngó thử một số mặt báo. Thật bất ngờ là hầu hết chẳng báo nào xóa metadata hết. Có trường hợp họ làm không tới, ví dụ như chỉ xóa metadata ở trong bài viết, nhưng cái thumbnail thì để nguyên không xóa. Thế là blog này ra đời.
Xem xét trường hợp sau đây:
Đây là ảnh người dân trên một trang báo dấu tên mà tôi ngẫu nhiên tải về. Khi thử dùng tool khai thác metadata, dữ liệu trả về rất đầy đủ.
Với thông tin về GPS Position, ta có thể tìm ra địa chỉ của người dân này.
Việc tìm ra địa chỉ tưởng chừng vô thưởng vô phạt này, thực tế lại tiềm ẩn nhiều rủi ro. Ví dụ như đây là một phóng sự phải giữ bí mật danh tính người được phỏng vấn, hoặc là một buổi làm việc tại nhà riêng của người nổi tiếng… Các thông tin này hoàn toàn có thể bị lộ ra, để lại các hệ lụy nghiêm trọng.
Tiến hành khai thác
Mục tiêu của tôi là các trang báo ở Việt Nam (vì thầy tôi bảo họ chưa quan tâm đến vấn đề này lắm). Các đầu báo được chọn lọc dựa trên độ uy tín và độ phổ biến. Cụ thể là dùng google với keyword “báo” và chọn ra những đầu báo quen thuộc. Các bạn có thể xem các đầu báo được lựa chọn ở bên dưới.
Để kết quả được khách quan và chính xác, mỗi báo tôi sẽ lấy 1000- 1500 mẫu ảnh ở tất cả các đường dẫn của trang báo. Các ảnh được lấy mẫu sẽ có thời gian chụp/đăng trong năm 2024. Để giảm thiểu thời gian thao tác, tôi có viết một con tool bằng python để tải hết ảnh trên các trang web về, các bạn có thể xem ở cuối bài viết. Code chưa được tối ưu nhưng đạt hiệu quả tôi mong muốn. Và tôi phải viết nó vì code trên github làm tôi bay màu kali, cũng may là máy ảo.
Sau khi đã lấy được đủ số lượng mẫu ảnh, việc của tôi là lọc ra hết những ảnh không sử dụng được. Cụ thể là những ảnh logo, gif, ảnh nền… Quá trình lọc mẫu diễn ra khá lâu, song lượng ảnh thực tế vẫn đạt 90% số ảnh ban đầu.
Bước cuối cùng là phân tích metadata bằng exiftool. Kết quả thu thập được cùng đánh giá sẽ được chia theo từng đầu báo dưới đây.
DANH SÁCH CÁC TRANG BÁO
✅ An toàn
✅ An toàn
⚠️ 36% lộ dữ liệu camera. Một nửa trong số đó có chứa dữ liệu GPS.
⚠️ Các thiết bị chứa dữ liệu GPS chủ yếu là điện thoại Pixel, Flycam; một phần nhỏ là iPhone. Ngoài ra một số thiết bị còn chứa cả tên chủ sở hữu.
✅ An toàn
⚠️ Chỉ xóa metadata trên ảnh bài viết. Ảnh thumbnail vẫn giữ nguyên.
⚠️ 40% lộ dữ liệu camera.
⚠️ 10% lộ dữ liệu GPS. Phần lớn lộ ở Pixel và Flycam, còn lại là iPhone.
⚠️ 35% lộ dữ liệu camera, 1/3 trong số đó là iPhone.
⚠️ 5% lộ dữ liệu GPS.
💡 Với báo chính phủ, số mẫu lấy nhỏ hơn vì sợ bị điều tra 🫥.
⚠️ Không xóa metadata. Hầu hết các ảnh được chụp bằng máy ảnh chuyên dụng vì là trang thông tin chính phủ. Tuy nhiên vẫn có vài ảnh chụp bằng Flycam và để lộ ra metadata. Ngoài ra còn phát hiện ảnh chụp bằng iPhone 😃.
✅ An toàn
⚠️ Không xử lý metadata nhưng không lộ nhiều thông tin vì không có người đóng góp và lấy ảnh mạng.
✅ An toàn, đã xóa các metadata nhạy cảm.
Không phải tất cả các báo được đánh dấu an toàn đều đã xử lý metadata từ đầu, và xử lý triệt để. Điển hình như VnExpress chỉ mới xử lý metadata từ khoảng cuối năm 2023 tới nay. Khi xem lại những bài viết từ tháng 09/2023, metadata vẫn còn tồn tại.
Kết luận
Các trang báo hiện đại đã quan tâm tới metadata và đã xử lý ảnh trước khi đăng lên trên trang của mình. Hầu như các trang báo bị lộ metadata đều là tờ báo truyền thống, phát triển thêm mảng báo mạng nhưng chưa để ý tới metadata, hoặc làm không tới, khiến cho những dữ liệu này dễ bị khai thác.
Các thiết bị được dùng để tác nghiệp phần lớn là các thiết bị chuyên dụng cho quay chụp như máy ảnh Canon, Nikon… và hầu như không hỗ trợ GPS nên metadata chỉ có các thông số ảnh. 10% đến 20% còn lại là các thiết bị như điện thoại, flycam… và cũng chính là nguồn gốc chủ yếu của những tấm ảnh có chứa GPS. Pixel là hãng điện thoại nổi tiếng về chất lượng quay chụp nên được sử dụng khá nhiều, song các ảnh cũng chứa rất nhiều thông tin, kể cả thông tin về vị trí ảnh chụp. Ngoài ra các nhà báo tự do cũng có xu hướng sử dụng iPhone để làm phóng sự.
Mọi người nên để ý tới cài đặt chụp ảnh trên điện thoại của mình, kiểm tra xem nó có đang lưu vị trí chụp ảnh không. Hầu hết các nền tảng mạng xã hội bây giờ như Facebook, Instagram… đều đã xử lý metadata. Nhưng nếu bạn upload ảnh trên một ứng dụng không xử lý, nguy cơ thông tin của bạn bị lộ là rất cao. Ai biết họ có thể làm gì với những thông tin đó.
Code
import os
from bs4 import BeautifulSoup
from urllib.parse import urljoin, urlparse
from PIL import Image
from io import BytesIO
import sys
import requests
from concurrent.futures import ThreadPoolExecutor
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
def download_image(img_url, directory):
try:
# Tạo đường dẫn tệp tin cho hình ảnh được tải xuống
filename = os.path.join(directory, os.path.basename(urlparse(img_url).path))
# Kiểm tra nếu URL chứa từ "svg" thì bỏ qua
if "svg" in img_url or "logo" in img_url:
return
# Tải xuống hình ảnh từ URL sử dụng requests
response = requests.get(img_url)
if response.status_code == 200:
# Mở hình ảnh từ nội dung của phản hồi
img = Image.open(BytesIO(response.content))
# Lưu hình ảnh vào thư mục được chỉ định và bảo tồn metadata
img.save(filename, exif=img.info.get("exif"))
print(f"Đã tải xuống và lưu: {filename}")
else:
print(f"Lỗi khi tải xuống hình ảnh: {img_url}")
except Exception as e:
print(f"Lỗi: {str(e)}")
def download_images(url, directory):
try:
# Tạo thư mục nếu nó chưa tồn tại
if not os.path.exists(directory):
os.makedirs(directory)
# Khởi tạo trình duyệt Selenium
driver = webdriver.Chrome()
driver.get(url)
# Cuộn trang web xuống dưới cùng để tải xuống tất cả các phần
last_height = driver.execute_script("return document.body.scrollHeight")
while True:
# Cuộn đến dưới cùng của trang web
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# Chờ cho trang web tải dữ liệu mới
time.sleep(5)
# Tính toán chiều cao mới của trang web sau khi cuộn
new_height = driver.execute_script("return document.body.scrollHeight")
# Kiểm tra xem đã cuộn đến cuối trang web chưa
if new_height == last_height:
break
last_height = new_height
# Lấy nội dung HTML của trang web đã cuộn
soup = BeautifulSoup(driver.page_source, 'html.parser')
# Lấy tất cả các thẻ img từ trang web
img_tags = soup.find_all('img')
# Sử dụng ThreadPoolExecutor để tải xuống hình ảnh song song
with ThreadPoolExecutor(max_workers=10) as executor:
# Lặp qua từng thẻ img và gửi nhiệm vụ tải xuống hình ảnh cho ThreadPoolExecutor
for img_tag in img_tags:
img_url = urljoin(url, img_tag['src'])
executor.submit(download_image, img_url, directory)
except Exception as e:
print(f"Lỗi: {str(e)}")
finally:
# Đóng trình duyệt sau khi hoàn thành
driver.quit()
if __name__ == "__main__":
# Kiểm tra xem có đủ đối số đầu vào không
if len(sys.argv) != 3:
print("Sử dụng: python download_images.py <URL> <directory>")
sys.exit(1)
url = sys.argv[1]
directory = sys.argv[2]
# Gọi hàm download_images để tải xuống hình ảnh
download_images(url, directory)
a giỏi quá ạ