Increase reCaptcha Security - c#

I am using google recaptcha v2 in my application I'd integrate it in client side.
Here is my code
<script>
var onloadCallback = function () {
grecaptcha.render('recaptcha', {
'sitekey': '6Lc_qmcUAAAAAJW_kALWjxcxcvxcxcvxcvxc',
'callback': reCaptchaCallback,
});
};
var reCaptchaCallback = function (response) {
if (response !== '') {
console.log(response);
}
};
function getReCaptchaRes() {
var message = 'Please check the checkbox';
if (typeof (grecaptcha) != 'undefined') {
var response = grecaptcha.getResponse();
(response.length === 0) ? (message = 'Captcha verification failed') : (message = '');
}
$('#reCaptchaLblMsg').html(message).css('color', "red");
return !(response.length === 0)
}
submitHandler: function (form) {
// call the google recaptcha validation
if (getReCaptchaRes()) {
$('.spinner-holder').css('display', 'block');
$("#myAjaxRegisterModal2 input[type='submit']").val("Saving ...").attr('disabled', 'disabled');
var __RequestVerificationToken = $('[name="__RequestVerificationToken"]').val();
var RegisterData = {
__RequestVerificationToken: __RequestVerificationToken,
ProfileCreatedFor: $('#ddlProfileCreatedFor').val(),
GroomBrideName: $('#txtName').val(),
Mobile: $('#txtMobile').val(),
EmailID: $('#txtEmail').val(),
Height: $('#ddlHeight').val(),
Gender: $("input[name='Gender']:checked").val(),
MaritalStatus: $('#ddlMaritalStatus').val(),
DOBMonth: $('#ddlMonth').val(),
DOBDate: $('#ddlDate').val(),
DOBYear: $('#ddlYear').val(),
State: $('#ddlUserState').val(),
City: $('#ddlCity').val(),
Section: $('#ddlUserSection').val(),
DivisonText: $('#DivisonText').val(),
Password: $('#ConfirmPassword').val()
}
//form.submit();
$.ajax({
url: "/Home/RegisterNewMemberByJson",
type: "POST",
data: RegisterData,
dataType: 'json',
success: function (data) {
if (data == "Error") {
window.location.href = "/Home/Index";
}
else if (data == true) {
$('#myAjaxRegisterModal2').modal('hide');
RegisterPopUp();
}
else {
$('.spinner-holder').hide();
$("#myAjaxRegisterModal2 input[type='submit']").val("Save").removeAttr("disabled");
$('#ageErrorMsg').text(data);
}
}
});
}
}
<div class="clearfix"></div>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer>
</script>
But my concern is if I will change response from browser console then I can hit the ajax method multiple times using a loop. So how can I prevent it to hit my ajax method into loop Or there is something wrong with my captcha integration.
My another concern is is it possible to check the captcha response on the client side as well as on the server side. if possible then how.
Please help me any kind of help will be appreciated.

Now I can answer my own question. I was making a stupid mistake I was not sending the response through ajax and was trying to get the response into my method on controller through [g-recaptcha-response].
Here is the updated code.
public JsonResult RegisterNewMemberByJson(ReligionAndEthinicityModel RegisterData)
{
if (ModelState.IsValid)
{
try
{
bool captchaIsvalid = IsReCaptchValid(RegisterData.cResponse);
if (captchaIsvalid)
{
public bool IsReCaptchValid(string cResponse)
{
var result = false;
var captchaResponse = cResponse;
var secretKey = Convert.ToString(ConfigurationManager.AppSettings["RecaptchaKey"]);
var apiUrl = "https://www.google.com/recaptcha/api/siteverify?secret={0}&response={1}";
var requestUri = string.Format(apiUrl, secretKey, captchaResponse);
var request = (HttpWebRequest)WebRequest.Create(requestUri);
using (WebResponse response = request.GetResponse())
{
using (StreamReader stream = new StreamReader(response.GetResponseStream()))
{
JObject jResponse = JObject.Parse(stream.ReadToEnd());
var isSuccess = jResponse.Value<bool>("success");
result = (isSuccess) ? true : false;
}
}
return result;
}

Related

Why querystring after ajax call while using datatable checkboxes?

I am trying to save the data by selecting multi checkboxes in datatables. But after ajax call in the submit click the the ajax not hitting success function. It is showing querystring along with the controller/action.Like following
https://localhost:44307/Leaves/Approval?leaveApproveDataTable_length=10&id%5B%5D=11
This is my js
$(document).on('click', '.btn-Approve', function (e) {
var form = this;
var rows = $(table.rows({
selected: true
}).$('input[type="checkbox"]').map(function () {
return $(this).prop("checked") ? $(this).closest('tr').attr('leaveid') : null;
}));
rows_selected = [];
$.each(rows, function (index, rowId) {
console.log(rowId)
// Create a hidden element
rows_selected.push(rowId);
$(form).append(
$('<input>')
.attr('type', 'hidden')
.attr('name', 'id[]')
.val(rowId)
);
});
var remarks = $('#Remarks').val();
console.log($(this).closest('tr').attr('leaveid'));
$.ajax({
url: '/Leaves/LeaveApproval',
data: { approveId: rows_selected, remarks: remarks },
type: 'POST',
processData: true,
dataType: 'JSON',
success: function (result) {
console.log(result);
debugger;
if (result) {
window.location.href = "/Leaves/Approval";
}
else {
return result;
}
},
error: function () {
}
});
});
This is my controller
public async Task<IActionResult> LeaveApproval(List<int> approveId, string remarks)
{
foreach (int id in approveId)
{
var leave = await _context.Leaves.FindAsync(id);
if (leave == null)
{
return Json(new { success = false });
}
leave.Status = "Approved";
leave.Remarks = remarks;
leave.ApprovedDate = DateTime.Now;
_context.Update(leave);
await _context.SaveChangesAsync();
}
return Json(new { success = true });
}
Kindly help me to solve the issue.
While returning from the controller replace:
return Json(new { success = true }); this line with
return Json(new { success = true }, JsonRequestBehavior.AllowGet);

How to send a file data to controller method with angularjs?

My project is Asp.net MVC Core.
I try to upload a file with angularjs to mvc controller but i make some mistakes; sending value is null in method. I can write a console log , actually data is not null but problem is sending to the controller.
angular.module("myApp").controller("myVm", function ($scope, $http, $window) {
var vm = $scope;
var url = "UploadSingle";
var config = {
headers: {
"Content-Type": undefined,
}
};
vm.upload = function () {
var formData = new $window.FormData();
formData.append("file-0", vm.files[0]);
console.dir(formData);
$http.post(url, formData, {
transformRequest: angular.identity,
headers: new HttpHeaders().set('enctype', 'multipart/form-data')
}).
then(function (response) {
vm.result = "SUCCESS";
vm.data = response.data.data;
}).catch(function (response) {
vm.result = "ERROR " + response.status;
});
};
public async Task<JsonResult> UploadSingle(IFormFile formData)
{
using (var reader = new StreamReader(formData.OpenReadStream()))
{
var fileContent = reader.ReadToEnd();
var parsedContentDisposition = ContentDispositionHeaderValue.Parse(formData.ContentDisposition);
var fileName = parsedContentDisposition.FileName;
}
return Json(new { result = "Test" });
}

How to send anti forgery token with Ajax file upload?

I'm trying to upload file(s) with an ajax call and validate the anti forgery token. I've had a look around and built a method to validate the anti forgery token on the controller. However whenever I have #Html.AntiForgeryToken on the view, my files do not get populated. Even though it validates the anti forgery token. It doesn't seem to be getting sent with the request but I'm unsure why.
ajaxSendOverride:
$(document).ready(function () {
var securityToken = $('[name=__RequestVerificationToken]').val();
$(document).ajaxSend(function (event, request, opt) {
if (opt.hasContent && securityToken) { // handle all verbs with content
var tokenParam = "__RequestVerificationToken=" + encodeURIComponent(securityToken);
opt.data = opt.data ? [opt.data, tokenParam].join("&") : tokenParam;
// ensure Content-Type header is present!
if (opt.contentType !== false || typeof event.contentType !== 'undefined') {
request.setRequestHeader("Content-Type", opt.contentType);
}
}
});
});
Ajax:
$(document).on("submit", "[data-upload-contract-form]", function (e) {
e.preventDefault();
var formData = new FormData($('[data-upload-contract-form]')[0]);
if ($('[data-upload-file]').val() != "") {
$.ajax({
url: $(this).attr('action'),
data: formData,
type: 'POST',
processData: false,
contentType: false,
headers: {
'__RequestVerificationToken': $('[name=__RequestVerificationToken]').val()
},
success: function (data) {
if (data.Success === true) {
$('[data-contract-error-message]').text();
ReturnDataTableForUploadFile($('[data-upload-file-supplier-contract-id]').val());
table.ajax.reload();
}
else {
$('[data-contract-error-message]').show();
$('[data-contract-error-message]').text(data.ResponseText);
}
}
})
.fail(function () {
$('[data-contract-error-message]').show();
$('[data-contract-error-message]').text("Something went wrong uploading your file, please try again.");
});
}
else {
$('[data-contract-error-message]').show();
$('[data-contract-error-message]').text("No contract to upload");
}
});
Validation:
public sealed class AuthorizeAntiForgeryToken : System.Web.Mvc.FilterAttribute, System.Web.Mvc.IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var httpContext = filterContext.HttpContext;
var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
AntiForgery.Validate(cookie != null ? cookie.Value : null,
httpContext.Request.Headers["__RequestVerificationToken"]);
}
}
Controller:
public async Task<JsonResult> UploadContract(UploadContract model)
{
if (ModelState.IsValid)
{
try
{
foreach (var item in model.Contracts)
{
string filePath = WebConfigurationManager.AppSettings["SupplierContractPath"] + GetSelectedClientId() + "\\" + item.FileName;
_supplierFileManager.UploadFile(item, filePath);
await _supplierFileManager.SaveContractToDatabase(model.SupplierContractID, item.FileName);
}
return Json(new { Success = true });
}
catch (Exception e)
{
return Json(new { Success = false, ResponseText = e.Message });
}
}
else
{
string errorMessage = "";
foreach (var item in ModelState.Values.SelectMany(r => r.Errors))
{
errorMessage += "<p>" + item.ErrorMessage + "</p>";
}
return Json(new { Success = false, ResponseText = errorMessage });
}
}
How can I send my files with the anti forgery token?
I ran into this problem myself today and ran into this question without an answer. The links to other answers didn't work, but after a while I found the solution.
The anti-forgery token has to be in a form field, not a header. It also has to be the first field in the form data. So to solve it, do:
$(document).on("submit", "[data-upload-contract-form]", function (e) {
e.preventDefault();
var formData = new FormData();
formData.append('__RequestVerificationToken', $('[name=__RequestVerificationToken]').val());
formData.append('file', $('[data-upload-contract-form]')[0]);
if ($('[data-upload-file]').val() != "") {
$.ajax({
url: $(this).attr('action'),
data: formData,
type: 'POST',
processData: false,
contentType: false,
success: function (data) {
if (data.Success === true) {
$('[data-contract-error-message]').text();
ReturnDataTableForUploadFile($('[data-upload-file-supplier-contract-id]').val());
table.ajax.reload();
}
else {
$('[data-contract-error-message]').show();
$('[data-contract-error-message]').text(data.ResponseText);
}
}
})
.fail(function () {
$('[data-contract-error-message]').show();
$('[data-contract-error-message]').text("Something went wrong uploading your file, please try again.");
});
}
else {
$('[data-contract-error-message]').show();
$('[data-contract-error-message]').text("No contract to upload");
}
});
My own function (using jQuery) which works fine: (it's not complete, but at least it reports back it received the file ;))
<script type="text/javascript">
function uploadFileThroughForm(messageId) {
var form = $('#addAttachmentForm');
if (form.valid()) {
var files = $('#filenameToUpload').prop('files');
if (files.length > 0) {
if (window.FormData !== undefined) {
var formData = new FormData();
formData.append("__RequestVerificationToken", $('#addAttachmentForm input[name=__RequestVerificationToken]').val());
formData.append("file", files[0]);
$.ajax({
type: "POST",
url: '#ApplicationAdapter.GetVirtualRoot()Attachment/Add/' + messageId,
contentType: false,
processData: false,
data: formData,
success: function(result) {
alert(result.responseMessage);
},
error: function(xhr) {
alert(xhr.responseText);
}
});
} else {
alert("This browser doesn't support HTML5 file uploads!");
}
}
}
}
</script>
Hope this helps, even if it's been a while since you asked this question!

Sending object to a controller in asp.net mvc using ajax

I have issue with sending object contains array to a controller
this is my js code
var messageId = 0;
function DraftMessage()
{
var to = [];
var i = 0;
$('#to option:selected').each(function (index, element) {
to[i++] = $(element).val();
});
console.log(to);
$.ajax({
type: "POST",
url: "#Url.Action("DraftMessage", "Activities")",
datatype: "json",
traditional: true,
async: false,
data: { "id": messageId, "To": to, "Title": $("#title").val(), "Project": $("#project").val(), "AreaId": $("#areaId").val(), "Body": $("#messageBody").val() },
beforeSend: function () { }
}).done(function (Id) {
console.log(Id);
messageId = Id;
});
}
$("input, select, textarea").change(function () { DraftMessage(); });
var contents = $('.note-editable').html();
$(".compose-message").on("blur", ".note-editable", function () {
if (contents != $(this).html()) {
DraftMessage();
contents = $(this).html();
}
});
and this is my controller side
public int DraftMessage(message draftMessage, HttpPostedFileBase[] files = null)
{
return new MessageActions().DraftMessage(draftMessage);
}
my issue is that the ajax request always send the to array as null, I do not know what is wrong so could anyone help me to resolve this issue.
Can you change your request and use
dataType: "json",
contentType: "application/json;charset=utf-8",
This should work. Please let me know.
Try this. Push your object to array and send it as Json.
array.push({yourobject datas here})
$.ajax({
type: "POST",
url: '/DraftMessage/Activities',
contentType: 'application/json',
data: JSON.stringify(array),
success: function (d) {
..
},
error: function (xhr, textStatus, errorThrown) {
console.log(errorThrown);
}
});
Convert your controller function's return type to JSonResult.
Hope helps.
do you want upload file using ajax ?!!
use the normal usage of form not the Ajax.BeginForm then in form submit event
write your code like this:
$('#Form').submit(function () {
var xhr = new XMLHttpRequest();
var fd = new FormData();
var file = $('#Image').val();
if (file) {
var fname = $('#Image')[0].files[0].name;
if (CheckFile(file)) {
var uploadFile = document.getElementById('Image').files[0];
var myArray = [];
myArray.push(uploadFile);
if (myArray.length > 0) {
for (var i = 0; i < myArray.length; i = i + 1) {
fd.append("File1", myArray[i]);
}
}
}
else {
return false;
}
}
fd.append("ID", messageId);
fd.append("Title", $('#Title').val());
fd.append("Project", $('#Project').val());
fd.append("AreaId", $('#AreaId').val());
fd.append("Body", $('#messageBody').val());
var form = $('#Form');
var token = $('input[name="__RequestVerificationToken"]', form).val();
fd.append("__RequestVerificationToken", token);
xhr.open("POST", "/ControllerName/Action/", true);
xhr.send(fd);
xhr.addEventListener("load", function (event) {
if (event.target.response != "OK") {
OnFail(event.target.response);
}
else {
OnSuccess(event);
}
}, false);
return false;
})
server side in controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult actionName(Model pModel){
HttpPostedFileBase File = Request.Files["File1"];
if (File != null && File.ContentLength != 0){
//do what you want
return Content("OK");
}
else{
Response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
return Content("Error Messages", System.Net.Mime.MediaTypeNames.Text.Plain);
}
}
You can try a different approach. You can serialize your entire form by doing something like this:
var formdata = $("#frmEmailInfo").serialize();
and then post it to the Controller:
$.ajax(
{
type: "POST",
data: formdata,
dataType: 'json',...

How to collect JSON in c# posted from angularjs?

I'm a basic developer, I just need to collect the following JSON data in a c# file:
{
"text":"This is a message !!!",
"userid":"some_id",
"username":"username",
"fname":"some_name",
"lname":"some_surname",
"iurl":"url_here",
"type":"some_type"
}
The above array is posted using angularjs.
app.js:
var app = angular.module('myApp');
app.controller('WorkingCtrl', ['$scope', '$http', function ($scope, $http) {
$scope.form = {};
$scope.post = [];
$scope.submitForm = function () {
$scope.post.text = $scope.form.text;
if ($scope.post.text != '') {
$scope.post.unshift($scope.post.text);
$scope.post.text = '';
}
$scope.remItem = function ($index) {
$scope.post.splice($index , -1);
}
$scope.form.userid = "some_id";
$scope.form.username = "username";
$scope.form.fname = "some_name";
$scope.form.lname = "some_surname";
$scope.form.iurl = "url_here";
$scope.form.type = "some_type";
$scope.showValues = JSON.stringify($scope.form);
}
}]);
As clearly seen above showValues returns the array.
Now I just wanted to collect data in my ValuesController.cs file. Can anyone suggest how to do that ?
You could also try this code:
Create a service.
app.service("angularService", function ($http) {
this.AddValues= function (showValues) {
var response = $http({
method: "post",
url: "api/values/YourmethodName",
data: showValues
});
return response;
}
});
In your controller: Inject your Service here in this way to implement its method/service
app.controller('WorkingCtrl', ['$scope','angularService',function ($scope, angularService) {
$scope.submitForm = function () {
$scope.form = {};
$scope.form.userid = "some_id";
$scope.form.username = "username";
$scope.form.fname = "some_name";
$scope.form.lname = "some_surname";
$scope.form.iurl = "url_here";
$scope.form.type = "some_type";
$scope.showValues = JSON.stringify($scope.form);
angularService.AddValues(showValues ).then(function (result) {
}
}]);
You should create a service which sends the data to your controller. You need something along these lines:
app.factory('WorkingService', ['$http', '$q', function ($http, $q) {
saveData: function (showValues ) {
var deferred = $q.defer();
$http.post(yourMVCUrl, showValues ).then(function (result) {
deferred.resolve(result);
});
return deferred.promise;
}
}
In your angular controller, just call the service WorkingService.saveData($scope.form).
You can make call to your MVC controller (ValuesController.cs) using this code in your Angular controller:
$http({
method: 'POST',
url: '/Values/TestMethod',
data: $scope.showValues,
headers: { 'content-type': 'application/json' }
}).
success(function (data) {
//do some operations with the return data if the MVC controller returns data
}).
error(function () {
alert("Error has happened..");
});
It is better to put the ajax request in a factory service and from your controller to call the http method from the service

Categories