Làm sao để ngăn người dùng nhấn submit form nhiều lần ?
Mình có một cái form nhưng không làm sao ngăn người dùng submit nhiều lần được. Có tìm hiểu trên mạng thì có vài ý kiến.
- Dùng javascript disable button, form ... cách này không ổn vì nó chỉ giải quyết phía client sẽ ko triệt để được .
- Xử lý phía sever . đây là cách mình cần dùng nhưng chưa thể làm triệt để được.
Trong Laravel mình tham khảo cách này nhưng cũng ko ngăn được họ click nhiều lần.
File Controller
public function postTest(Request $r){
if($r->form_token != session('form_token'))
{
echo '<br/> Access denied';
} else {
echo '<br/> Work';
$px = new PhieuXuat();
$px->author = session('ID');
$px->title = session('form_token') ;
$px->khohang = $r->form_token ;
$px->tinh = $r->name ;
$px->save();
}
$this->chuongtrinhA();
$this->chuongtrinhB();
$this->chuongtrinhC();
Session::put('form_token', '');
}
public function chuongtrinhA(){
$px = new PhieuXuat();
$px->author = 11;
$px->title = 'TitleAAA';
$px->save();
}public function chuongtrinhB(){
$px = new PhieuXuat();
$px->author = 11;
$px->title = 'TitleBBB';
$px->save();
}public function chuongtrinhC(){
$px = new PhieuXuat();
$px->author = 11;
$px->title = 'TitleCCC';
$px->save();
}
File View
<?php
/*** begin the session ***/
/*** create the form token ***/
$form_token = uniqid();
Session::put('form_token', $form_token); //$value = Session::get('key');
?>
<form action="{{route('postTest')}}" method="post">
<input type="hidden" name="form_token" value="<?php echo $form_token; ?>" />
<div>
<label for="name">Name</label>
<input type="text" name="name" />
<div>
<div>
<input type="submit" value="Add Name" />
</div>@csrf()
</form>
Với cách này khi mình cố tình click thật nhanh thì nó vấn insert dữ liệu nhiều lần. Đang bế tắc quá.
3 CÂU TRẢ LỜI
Dùng javascript disable button, form ... cách này không ổn vì nó chỉ giải quyết phía client sẽ ko triệt để được
Cách này trên thực tế lại khá hiệu quả, và được vài framework như mình biết là Rails (https://guides.rubyonrails.org/working_with_javascript_in_rails.html#automatic-disabling) dùng để ngăn người dùng double click.
Trong trường hợp cần ngăn chặn triệt để hơn ở phía backend, một cách đơn giản là chỉ cần thêm rate-limit để cùng một người dùng không thể submit quá nhiều lần trong khoảng thời gian ngắn. Giống như cách đa số các mã nguồn diễn đàn dùng, mỗi lần người dùng đăng bài/lập thread mà bài đăng gần nhất của họ đăng cách đây không lâu thì trả về thông báo lỗi.
Thực ra cái này phụ thuộc vào người dùng submit form nhiều lần vô tình
hay cố tình
. Và việc họ click nhiều lần hay không bản chất vẫn là việc gửi - nhận dữ liệu giữa client và server thông qua giao thức HTTP
. Bạn có thể hạn chế người dùng bằng cách disable
các button, nhưng còn việc họ dùng tool cố tình call các đầu api để insert nhiều dữ liệu vào database của mình thì sao
Với user vô tình submit form thì bạn có thể sử dụng cách như bạn đã nói ở đầu bài, với một người non-tech thì họ cũng không có nhiều kiến thức để có thể sửa các element hay F12 chỉnh sửa các attribute. Nên mình nghĩ cách bên dưới là hợp lí.
Dùng javascript disable button, form ... cách này không ổn vì nó chỉ giải quyết phía client sẽ ko triệt để được
Với user cố tình phá hoại hệ thống thì họ có rất nhiều cách để insert nhiều bản ghi vào trong hệ thống của mình nếu như bạn không validate và có những cơ chế limit request
hợp lí. Mình thấy có một số cách cơ bản sau bạn có thể tránh được việc này.
-
Validate
đầu vào chặt chẽ, ví dụ như bạn có một cái form register thông tin user, đảm bảo rằng ở tầng application(cụ thể là Laravel sử dụng form request để validate thông tin email là unique). Ngoài ra bạn còn có thể validate input thông qua việclooking row
, hay là đánh các trường trong database làunique
để đảm bảo việc dữ liệu không bịduplicate
trong một số trường hợp. -
Limit request
gửi lên server. Ví dụ như 1 phút với một phiên đăng nhập của người dùng chỉ được phép request tối đa 60 request chẳng hạn.Ưu điểm là setting rất dễ, cả ở tầng server và application, ví dụ như Laravel đã config sẵn cho chúng ta trong
app/Http/Kernel.php
Nhược điểm là họ có thể
fake IP
để loại bỏ việc limit request.
'api' => [
'throttle:60,1',
'bindings',
],
-
Sử dụng
capcha
, đối với mỗi form request màhay bị tấn công
, hãy sử dụng capcha để đảm bảo rằng kẻ phá hoại không thể cùng lúc tiến hành call nhiều request lên server.Ưu điểm của phương pháp này là có thể giải quyết được bài toán fake IP phía trên
Nhược điểm là đem lại phiền toán cho người dùng bình thường, nhập
capcha everywhere
. Và việc triển khai cũng mất nhiều thời gian -
Sử dụng một số
tool monitoring
hệ thống, kịp thời phát hiện ra các IP khả nghi, phá hoại hệ thống để block hoặc đưa ra các phương pháp hạn chế người dùng hợp lí
Ngoài ra còn rất nhiều phương pháp nữa nhưng hi vọng các gợi ý trên đây có thể giúp đỡ được bạn
Cảm ơn bạn đã phản hồi rất dài, rất có tâm luôn. Mình đang cần phải chống lại sự phá hoại nên các cách sử dụng phía client như jquery disable nút submit gần như ko dùng được. Cách giải quyết limit resquest thì là ok nhất nhưng vẫn ko hiểu sao nó lại không hoạt động. Mình đã làm thử 1 form submit bình thường insert dữ liệu vào db sử dụng session bên trên mình click thật nhanh 2 phát liền nó vẫn insert.
@tinhtn89 Thế chỗ submit kia bạn sửa lại type bằng button đi, sau đó sử dụng Jquery để submit form, mình nghĩ lúc đó có thể xử lí được việc disbale button.
https://stackoverflow.com/questions/1200266/submit-a-form-using-jquery
Bạn nên set thêm trường timestamp cho mỗi insert record, rồi lấy timestamp vừa submit so sánh với timestamp ở record mới nhất, vd là một phút thì time ở submit trừ đi time ở record phải lớn hơn 1p rồi mới query insert... nếu sợ ảnh hưởng đến các client submit khác thì bạn nên fillter dữ liệu theo trường unique nữa nha.
- Cách làm disable ở web là đúng rồi.
- Còn về BE: có thể tạo 1 queue để xử lý tuần tự / đồng thời theo một limit nhất định hoặc limit by id từ client gửi lên trong khoảng thời gian cho phép.