Lỗi Tracking-Link làm hỏng các Signed URL
Một lỗi có thể trở nên nguy hiểm nếu nó chỉ làm hỏng những thứ quan trọng nhất.
Tôi đã tìm thấy một lỗi trong mail-history, nó hoạt động hoàn hảo với các liên kết thông thường nhưng lại thất bại với các signed URL. Nó làm hỏng các liên kết xác thực email và các liên kết tải xuống có chữ ký. Đây là những liên kết mà chỉ cần một ký tự sai cũng khiến Laravel từ chối yêu cầu.
Dưới đây là cách nó đã xảy ra.
mail-history theo dõi các lượt nhấp chuột trong email bằng cách viết lại mã HTML của bạn. Nó thay đổi mọi liên kết để điều hướng qua một redirect endpoint trước. Endpoint này sẽ ghi lại lượt nhấp và sau đó gửi người dùng đến đích thực sự.
Để làm điều này, hệ thống mã hóa URL gốc thành một tracking link.
Vấn đề bắt đầu khi hệ thống lấy URL từ HTML đã được render. Vào thời điểm mã nguồn đọc nội dung email, Laravel đã thực hiện escape HTML. Một ký tự ampersand (&) trong liên kết sẽ trở thành &.
Một liên kết thông thường như https://example.com/page hoạt động bình thường. Nó không có ký tự ampersand.
Nhưng một signed URL sẽ trông như thế này:
https://example.com/email/verify/1/abc?expires=123&signature=deadbeef
Trong HTML, nó trở thành:
https://example.com/email/verify/1/abc?expires=123&signature=deadbeef
Mã nguồn mã hóa chuỗi & đó. Khi người dùng nhấp vào, hệ thống giải mã nó và gửi họ đến một URL chứa &. Laravel cố gắng xác thực chữ ký, nhưng việc xác thực thất bại vì các ký tự không khớp với bản gốc.
Cách khắc phục chỉ nằm trong một dòng mã. Bạn phải giải mã các HTML entities trước khi mã hóa URL.
$originalUrl = html_entity_decode($matches[2], ENT_QUOTES | ENT_HTML5);
Điều này chuyển & trở lại thành & trước khi quá trình mã hóa diễn ra. Liên kết sau khi giải mã giờ đây khớp chính xác từng byte với signed URL gốc.
Tôi cũng đã thêm một bài kiểm tra (test) để ngăn chặn điều này tái diễn. Bài test này kiểm tra xem URL sau khi giải mã có chứa ký tự & thực sự hay không, chứ không phải &.
Những bản sửa lỗi nhỏ như thế này rất dễ bị mất đi trong các đợt dọn dẹp mã nguồn (code cleanup) sau này. Hãy luôn viết một bài test chỉ rõ lỗi cụ thể đó.
Bài học cho bạn:
- Nếu bạn trích xuất dữ liệu từ HTML đã được render, hãy mặc định rằng nó đã được escape.
- Trình duyệt sẽ tự sửa các ký tự đã được escape cho bạn. Việc mã hóa và redirect thì không.
- Sử dụng các bài test để bảo vệ những bản sửa lỗi chỉ vỏn vẹn một dòng.
Source: https://dev.to/nasrulhazim/the-tracking-link-bug-that-only-breaks-signed-urls-38c
