Tại sao Portal của trường cứ lỗi mãi?

Context

Tình hình là mình đang ngóng chờ điểm môn học cuối cùng từng ngày, vì đó là số điểm quyết định đợt này mình có ra trường không chứ bám ở trường 7 năm rồi cũng ngán. Tuy nhiên, mỗi lần vào xem bảng điểm, thứ chào đón mình lại không phải là bản điểm, mà là cái thông báo này:

portal error message
💩💩💩

Hoặc thế này:

“Mất chữ”

Tệ hơn thì thế này

Bị đá về trang login luôn, phải đăng nhập lại 🙏

Nhân dịp đang bị bí bug bên dự án chính nên mình quyết định sẽ thử ngó 1 vòng xem đâu là nguyên nhân dẫn đến các lỗi trên.

Lưu ý: bài viết này chỉ mang tính chất học tập và tham khảo, không hoàn toàn bôi nhọ bất kỳ tổ chức hay cá nhân nào

Tìm hiểu các bên có liên quan

Trước tiên, mình muốn biết nguồn gốc portal này là của bên nào phát triển, là của trường mình tự phát triển hay thuê một bên thứ 3 để phát triển. Việc tìm kiếm này không có gì khó khăn, khi ở trên trang login của Portal có để tên đơn vị phát triển chính là PSC.

Lướt qua PSC thì họ là tổ chức có kinh nghiệm nhiều năm trong lĩnh vực xây dựng hệ thống quản lý tín chỉ, mò qua source code thì còn thấy mã trường UEH (Đại học Kinh tế TP. Hồ Chí Minh), nên mình nghĩ họ khá tín. Nhưng tại sao một đơn vị có tuổi nghề cao mà lại để lỗi trên xuất hiện thường xuyên mà không thấy có động thái sửa nào? Hay lỗi trên không thuộc về họ?

Lã lướt qua đống lỗi

Nói sơ qua về lỗi “Hệ thống lỗi“, lỗi này khá là ngẫu nhiên, nếu mình vào mà không bị lỗi trên thì page render ra hoàn toàn bình thường, bảng điểm sẽ được hiển thị ngay sau đó, nhưng một khi đã bị báo “Hệ thống lỗi” thì chắc chắn bản điểm sẽ không được trả ra.

Phán đoán của mình hệ thống phát triển theo client side và backend side riêng biệt và lỗi trên là lỗi API, mà lỗi API hên xui vậy thì mình cũng chịu, chẳng lẽ lỗi liên quan đến Database hay đọc file bên dưới hệ thống? Do mình là end-user đối với trường nên không biết chi tiết bên trong, nên thứ duy nhất mình có thể làm lúc này là bật devtool lên và xem response của lỗi.

Response lỗi của API

🤔 Mã lỗi 513, quái lạ, standard của HTTP response code làm gì có mã lỗi 513? Mã lỗi 5xx trải dài từ 500 đến 511, browser chỉ hỗ trợ từ 500 đến 504 thôi, vậy mã lỗi 513 có ý nghĩa gì? Chắc chắn mã lỗi này do phía server chủ động trả về, còn bên phía response body cũng không có bất kỳ nội dung nào.

Nói thêm nữa là API này lúc trả về bình thường, lúc thì bị lỗi như trên 🫠

Ấy mà khoan, nếu để ý phần Response Headers thì header Server có trả về 1 thông tin khá hay: Antiddos.vn. Điều này đồng nghĩa, bên phía trường hoặc PSC có thuê dịch vụ chống DDoS cho portal, và service này sẽ nằm ở giữa đường truyền từ user đến server của trường, mọi request mình gửi đến Portal đều phải đi qua Antiddos.vn để họ kịp thời chặn. Vậy có khi mã lỗi 513 kia là của… Antiddos.vn?

Để kiểm chứng thông tin này, mình qua Console và thử spam đến API của trường xem bằng code:

setInterval(() => {
    fetch("https://portal_api.vhu.edu.vn/api/authenticate/getmenu?language=vi", {
  "headers": {
    "accept": "application/json, text/plain, */*",
    "accept-language": "en-US,en;q=0.6",
    "apikey": "***",
    "authorization": "Bearer ***",
    "clientid": "vhu",
    "sec-ch-ua": "\"Brave\";v=\"125\", \"Chromium\";v=\"125\", \"Not.A/Brand\";v=\"24\"",
    "sec-ch-ua-mobile": "?0",
    "sec-ch-ua-platform": "\"Windows\"",
    "sec-fetch-dest": "empty",
    "sec-fetch-mode": "cors",
    "sec-fetch-site": "same-site",
    "sec-gpc": "1"
  },
  "referrer": "https://portal.vhu.edu.vn/",
  "body": null,
  "method": "GET",
  "credentials": "include"
})
}, 100);  

Đoạn này sẽ spam vào API /getmenu mỗi 100 milli giây, và ú òa:

Giao diện slow down của Antiddos.vn

Giao diện slow down của Antiddos.vn chính thức hiện ra và “ERROR 513“, vậy là xác nhận lỗi API đầu tiên là lỗi do Antiddos chặn khi vượt quá Rate Limit.

Lỗi “mất chữ”

Lỗi mất chữ cũng tương tự như trên, khi UI render ra, chúng sẽ hiển thị placeholder và sau đó sẽ replace thành “chữ đọc được” sau khi đã biết được ngôn ngữ đã chọn của end-user. Ví dụ user chọn ngôn ngữ anh thì giao diện phải hiển thị ngôn ngữ anh và tương tự với các ngôn ngữ khác.

Bộ API của trường có 1 API trả về bộ ngôn ngữ theo setting của user qua endpoint /GetResourceLanguage. Và thêm một lần nữa, khi bị Antiddos chặn, UI sẽ bị như ảnh.

Bị đá về trang login

Nếu nói toàn bộ các vấn đề xuất phát là do Antiddos thì không đúng, vì bên phía PSC vẫn có 1 số vấn đề trong việc handle lỗi của response.

Cụ thể về lỗi này thì khi bạn bị báo “Lỗi Hệ Thống” và cố gắng refresh lại trang, sẽ có khả năng cao bạn bị đá về trang login. Và bất ngờ hơn nữa, chỉ cần refresh lại trang login, bạn được đưa vào lại bên trong mà không cần phải login =))

Để hiểu về lỗi này thì cần quay ngược lại API /getmenu. API này cho phép truyền query param là “language“, truyền đúng language nào, thì backend sẽ trả về menu với ngôn ngữ tương ứng. Do mình để giao diện của mình là Tiếng Việt nên API sẽ truyền “vi” -> /getmenu?language=vi

Nhưng mà bên phía PSC xử lý hơi “kỳ”, có lẽ do không kiểm soát được useEffect của React (giao diện được viết bằng React), nên thành ra UI sẽ gọi API này tận 2 lần:

/getmenu?language=undefined
/getmenu?language=vi

Lần đầu gọi với param là “undefined”, có lẽ do chưa load đc userdata mà đã gọi, sau khi lấy được userdata thì họ lại gọi thêm 1 lần với param “vi”.

API getmenu này có lẽ quan trọng nên nếu lần gọi /getmenu?language=undefined mà bị thất bại, PSC xử lý rằng sẽ đá qua Component “Login”.

Đào sâu thêm 1 tý nữa, khi mình bị đá sang trang login này, ở devtool, mình kiểm tra các mục Cookie, Local và Session Storage để xem họ có xóa “trạng thái đã đăng nhập” không. Và kết quả là không.

Họ lưu thông tin cơ bản của user đã đăng nhập trong Local Storage, với key là “authorizationData“, và key này không bị xóa.

Mò trong file Javascript đã được mã hóa và “túm gọn” lại thì mình để ý đoạn này:

Mình không rõ số 14 kia là gì, nhưng đây là nội dung bên trong useEffect, mình đoán đây là 1 hàm xử lý lỗi khi không gọi được /getmenu, phần quan trọng ta thấy là:

u({
    type: "INITIALIZE",
    payload: {
        isAuthenticated: !1,  // !1 là false, tức đang khai báo trạng thái hiện tại là CHƯA ĐƯỢC LOGIN
        user: null,
        authmenu: null
    }
});

Nội dung bên trong hàm “u“:

Do là truyền giá trị false nên nó dính vào case if (!n.isAuthenticated). Còn nội dung bên trong chính là render ra page login.

Vậy là xong, PSC cũng có 1 phần lỗi trong việc handle lỗi.

Vậy… giờ sao?

Phần lỗi đá về trang Login thì handle khá dễ, do hệ thống thiết kế Client-side và Backend-side riêng biệt thì việc sửa lỗi không quá khó khăn nên thôi bỏ qua…

Còn về phần Antiddos, mình clear hết cache và thử hard refresh thì tổng số request khi ở page xem điểm là 36 – 43 requests trong 1.5 giây , sau đó mình chờ khoảng 1 giây sau và thực hiện hard refresh lại thì bị chặn.

Mình nghĩ là do họ thiết lập rate limit khá thấp, ước lượng lại con số phù hợp sao mà người dùng truy cập không bị chặn và vẫn chặn đúng những người dùng liên tục refresh mỗi khi đăng ký môn học.

Leave a Reply

Your email address will not be published. Required fields are marked *


The reCAPTCHA verification period has expired. Please reload the page.