I am using ASP.NET's generic handler (ASHX files) to make server-side pages that can return data to mobile apps and so on. Some of this data is ment to be private. I am using JSON & the POST method as of now.
However, anyone with access to a client-side code (for example the code of the Mobile App), would be able to see what keywords he has to send to the "unpredictable" URL in order to make changes or get data.
I've been doing research for hours and couldn't find a proper way to authenticate that the one sending the JSON request is indeed an approved mobile app.
Example of sending a request to the server with AJAX:
function login()
{
var jsonParam = { name: "test", aname: "secret", pass: "1234", type: "login" }
$.ajax({
url: "AppDatabase.ashx",
type: "post",
data: JSON.stringify(jsonParam),
dataType: "json",
contentType: 'application/json; charset=utf-8',
async:false,
success: function (response) {
alert(response.userEmail);
},
error: function(XMLHttpRequest, textStatus, errorThrown) {
alert("Status: " + textStatus + "\r\n" + "Error: " + errorThrown);
}
});
}
Example of receiving the request on the server side:
public void ProcessRequest (HttpContext context) {
context.Response.ContentType = "application/json";
JavaScriptSerializer jss = new JavaScriptSerializer();
context.Request.InputStream.Position = 0;
string json;
using (var reader = new StreamReader(context.Request.InputStream))
{
json = reader.ReadToEnd();
}
Dictionary<string, object> dict = jss.Deserialize<Dictionary<string, object>>(json);
if(dict["aname"].ToString() == "secret")
{
// The best security I have right now is a "secret keyword" within the request
}
}
Your current way is very dangerous.
You can use another page that needs username & password to authenticate (for ex. using Session) and then let client to request your ashx file and your ashx should check Session for authentication.
Just a thought:
Are clients (e.g. mobile app) "yours" or is this meant to be some sort of API (for x clients)?
Either way, maybe worth looking into JWT? The idea is that the "payload" (data) is signed (e.g. HMAC SHA-256) and has protections against "replays".
This way, you're not just looking to the auth part - re: both ends need to verify the data so both can ensure such data came from the "right origin" and is (still) valid.
Hth...
Related
I've got a serious problems with WebAPI and Token Key in ASP.NET IIS Server, I can acquire data very easy without security issue.
However I cannot obtain anymore from sever when I set up the [Authorize] in the any Controllers , because I didn't put the Authorization messages in the HTTP head, so how to put it in that ???
There had dealt with my question about how to use Ajax to get a Token key from Asp.net WebAPI. Hopefully this example can help someone who has the same question like me.
The client code will like as following ,it can get Token key from server ,however you have to add the user profile data in DB table first and then using client code to send user/pwd to server ,if user/pwd is correct it will be sent token key back by server
<script>
var token;
$("#getToken1").click(function () {
var user = {
grant_type: 'password',
username: '***#gmail.com',
password: '!aA1234'
};
$.ajax({
type: 'POST',
url: 'http://localhost:65370/Token',
data: user,
success: function (data) {
var parsedResponseBody = JSON.parse(JSON.stringify(data));
token = parsedResponseBody.access_token;
}
});
});
</script>
when you get token key,you will be passing Authorization checking and then you can get data from server site, like as following code
<script>
$("#read1").click(function () {
$.support.cors = true;
$.ajax({
crossDomain: true,
url: 'http://localhost:65370/api/travels',
headers: {
'Authorization': 'Bearer ' + token
},
type: 'GET',
success: function (data) {
alert(JSON.stringify(data));
}
});
});
</script>
Reference from https://www.theidentityhub.com/hub/Documentation/CallTheIdentityHubApi
I am sending a complex string (which is a combination of the style attribute, ID and label text) from the script using $.ajax() . I went through a couple of questions on similar problems. But maybe I am not able to understand where am I getting it wrong.
This is the script I am using :
$(".btnSaveStyle").click(function (e) {
var comp1Style = "";
var comp2Style = "";
$(".box").children(".comp1").each(function () {
var style = $(this).attr('style');
var title = $(this).text();
var componentClass = $(this).attr('class');
comp1Style = comp1Style + style + "#" + componentClass + "#" + title + "$";
});
alert(comp1Style); //I get the style here
$.ajax({
type: "POST",
async: true,
url: 'AjaxRecieveStyle.aspx/GetStyle',
data: comp1Style
});
And in the C# I am accessing it in the following way :
[WebMethod]
protected void GetStyle(string style)
{
var recievedStyle = style;
Customer customer = (Customer)Session["existing_user"];
if (customer != null)
{
EventComponent eventComponent = new EventComponent();
string txtComp1 = recievedStyle;
string[] separateComponents = txtComp1.Split('$');
string[] individualComponent = new string[5];
foreach (string position in separateComponents)
{
individualComponent = position.Split('#');
if (individualComponent[0].Equals(""))
{
//do nothing
}
else
{
eventComponent.EventID = 1;
eventComponent.Image = "";
eventComponent.Style = individualComponent[0].ToString();
eventComponent.ComponentType = individualComponent[1].ToString();
eventComponent.Title = individualComponent[2].ToString();
int id = new EventComponentLogic().Insert(eventComponent);
}
}
}
}
Now :
1) : Should I use a JSON object to pass the data ?
OR
2) : Please show me what am i doing wrong in here ?
1) Yes it's better to send data using JSON - I mean, it'd be much easier to understand what's happening when anyone will look at that code in a year from now. And it's also much easier to extend the protocol based on JSON.
2) I suggest you to add logging at the very beginning of the GetStyle(string style) method. Then please try to get to it by explicitly typing the URL in your browser (or better using PostMan - see below for a link, PostMan will help you with testing POST requests as I see you have a POST request there) and ensure that the web-server code works.
And only if it works then please try your front-end AJAX request.
I suppose that you don't handle POST request correctly in your WebAPI. It will only handle GET requests. Please look at this SO question for details: Simple post to Web Api
3) Link to PostMan: https://chrome.google.com/webstore/detail/postman-rest-client/fdmmgilgnpjigdojojpjoooidkmcomcm?hl=en
Did some digging and came up with this link: http://www.aspsnippets.com/Articles/Calling-ASPNet-WebMethod-using-jQuery-AJAX.aspx
The source code from the website shows that you may be missing some key features in your ajax call:
function ShowCurrentTime() {
$.ajax({
type: "POST",
url: "Default.aspx/GetCurrentTime",
data: '{name: "' + $("#<%=txtUserName.ClientID%>")[0].value + '" }',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: OnSuccess,
failure: function(response) {
alert(response.d);
}
});
}
While this is (obviously) intended for their example you see that they set the following attributes that you do not
contentType: "application/json; charset=utf-8",
dataType: "json",
success: OnSuccess,
failure: function(response) {
alert(response.d);
}
While the success and failure attributes are definitely optional I believe that setting your content type and datatype would really help you out here.
I changed my script to the following :
$.ajax({
type: "POST",
async: true,
url: 'AjaxRecieveStyle.aspx',
data: { style: comp1Style } //as I want to pass the parameter 'style' which is internally a JSON array.
});
I fetched the variable style in my C# in the following way (without using [WebServices]) :
I wrote a method GetStyle(string style) to get the data being sent from the ajax call.
Note: I did not call AjaxRecieveStyle/GetStyle from my script as the method is not accessible in my C# method . The data is actually received from the Page_Load method.
I access the variable sent from the script using Request.Params["style"].
My C# method is :
protected void Page_Load(object sender, EventArgs e)
{
GetStyle(Request.Params["style"]);
}
protected void GetStyle(string style)
{
var recievedStyle = style;
//do something on the recieved data!
}
This wil be an alternative to anyone who don't want to send JSON data actually !But sending data using JSON format will increase the readability of the code..
I am currently using AJAX to send a JSON object to a Handler written in C#. I was wondering if I can pass the JSON information through a simple url for debugging purposes, just like when I used to use simple parameters (queries) on URLs.
The C# handler deserializes the JSON into a class based on Name and Pass (strings).
So I am trying to go to the handler on the URL like this:
testHandler.ashx?Name=Hey&Pass=Check
Though the C# handler cannot deserialize that properly and the class object is null, if sent that way.
AJAX code of sending a working request to the web server:
var jsonParam = { Name: "test", Pass: "123" }
$.ajax({
url: "Test.ashx",
type: "post", //This sends in url
data: JSON.stringify(jsonParam),
dataType: "json",
contentType: 'application/json; charset=utf-8',
async:false,
success: function (response) {
alert(response.Name);
}
});
So I am wondering what this would look like, if sent through the browser on the URL text box.
P.S - I don't have a problem, I'm just trying to understand the work behind the serialization.
In the sample code you provided you are using JSON object serialized in the body of a POST request. Then you seem to be talking about some testHandler.ashx?Name=Hey&Pass=Check url where you are illustrating the values being passed as query string parameters. There's no longer JSON involved in this case. You should not be passing JSON payloads as parts of the query string. This is a perfectly valid request that you could achieve with the GET verb:
var jsonParam = { Name: "test", Pass: "123" }
$.ajax({
url: "Test.ashx",
type: "GET",
data: jsonParam,
dataType: "json",
success: function (response) {
alert(response.Name);
}
});
In this case you will obviously retrieve the values directly from the query string of course instead of doing any JSON deserialization in your handler:
public void ProcessRequest(HttpContext context)
{
string name = context.Request["Name"];
string pass = context.Request["Pass"];
context.Response.ContentType = "application/json";
...
}
Oh and by the way notice that I have removed the async: false switch from your code coz everytime I see this it makes me vomit.
I'm looking for an example of an ajax call for streaming data to a WCF service. I am always getting an error.
Any help appreciated, or even links to blogs with a solution.
This is my WCF service class
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class Images : IImages
{
string IImages.UploadImage(string fileKey, Stream imageStream)
{
using (var fileStream = File.Create(#"Images\" + fileKey))
{
imageStream.CopyTo(fileStream);
}
return "done";
}
}
and my contract is
[OperationContract(Name = "UploadImage")]
[WebInvoke(UriTemplate = "?file_key={fileKey}", Method = "POST", ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Bare)]
string UploadImage(string fileKey, Stream imageStream);
I have web.config stream binding
<binding name="PublicStreamBinding"
maxReceivedMessageSize="2000000000" transferMode="Streamed">
<security mode="None" />
</binding>
my ajax client call is like this
var data = '{"image":"' + uri + '"}'
$.ajax({
url: GetServerUrl()+"images.svc/?file_key="+options.fileKey,
type: "POST",
contentType: "application/json",
data: data,
success: function (result) {
console.log("SUCCESS");
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("error in transfer::" + jqXHR.responceText);
}
});
I can't comment on the server-side code, but client-side :
the data variable should be a plain javascript object, not a JSON representation
url shouldn't need the GetServerUrl() prefix; try a leading "/" instead
for a POST request it's more normal to include all parameters in the data object rather than tacking them onto the URL, which is the GET approach. It depends what the server-side code is set up to expect but as far as I can tell, it expects file_key to be in the POST.
You should end up with something like this :
var data = {
image: uri,
file_key: options.fileKey
};
$.ajax({
url: "/images.svc/",//probably
type: "POST",
contentType: "application/json",
data: data,
success: function (result) {
console.log("SUCCESS");
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("errror in transfer::" + jqXHR.responceText);
}
});
Install Fiddler ( www.telerik.com/fiddler ). Launch it. Make the web service call. Click on the record of the call in Fiddler. Click on the 'Raw' tabs for request and response. It will be enlightening and you will see exactly what is passed between server and client. Perhaps some addition WCF troubleshooting data as well in the response.
Also, don't forget to check your Application event log on the machine running the WCF service. You can also add a Global.asax to the WCF project (if its a web project) and put logging code in the Application_Error method. Something like this:
protected void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is ThreadAbortException)
{
// Nothing to do here. The thread abended.
}
else
{
activityMgr.Add(System.Reflection.MethodBase.GetCurrentMethod(), ex);
}
}
I'm developing a web site for mobile devices that makes ajax calls using jQuery (v 1.7.2) to an ASP.NET (v 2.0.50727) Web Service.
The call works correctly about 95% of the time, but it will randomly fail, returning a 500 internal server error. It fails on the server side before the first line of code is ever executed (the first line writes to the event log).
I haven't seen the call fail using a desktop browser that I remember, but I've seen it fail enough using an iPad. I added
<browserCaps userAgentCacheKeyLength="256">
to the Web Service's web.config file, but that hasn't helped.
javascript:
$.ajax({
type: "POST",
url: serverURL + "/getImage",
data: '{"formURL":"' + url + '", "rowNumber":"'+rowNumber+'"}',
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (msg,textStatus, jqXHR) {
...
}, error: function(xhr, ajaxOptions, thrownError) {
...
}
}).done(function(){
console.log("getImage call is done");
});
Example data passed to the web service:
'{"formURL":"fileName.xml", "rowNumber":"1"}'
c#
[WebMethod(EnableSession = true)]
[ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public string getImage(string formURL, string rowNumber) {
log("Retrieving image of form " + formURL);
string image = "";
string username = /*retrieve username*/;
string password = /*retrieve password*/;
if (username != null && username != "") {
image = /*code to retrieve the image*/;
}
return image;
}
private void log(string message) {
EvLog.WriteToEventLog(DateTime.Now.ToString("MM:dd:yyyy H:mm:ss:fff") + Environment.NewLine + message, 10);
}
The only thing I've found that has slightly helped me, is when the call fails because the response headers from the Web Service contain "jsonerror: true" though I haven't been able to pinpoint why it would randomly fail.
Any help is appreciated!
Assuming it truly is a JSON error, my first thought is that the data being passed into the parameters is incorrect.
The following line is quoting the contents of variables, which I assume is being loaded from somewhere else in the code:
data: '{"formURL":"' + url + '", "rowNumber":"'+rowNumber+'"}',
Assuming you are already making sure rowNumber is an integer value and wouldn't break it, the likelihood is that the 'url' variable is breaking your JSON format. The easiest way this could happen is if you had an unescaped quote in the filename, especially if it's closing your parameter values earlier than expected when it gets concatenated.
There's always the possibility of the characters not being valid for the charset. Do you have an example data that triggers the failure? The example provided looks nice and clean, so I'm assuming it wasn't one of the error cases.
Don't build your data in this way
data: '{"formURL":"' + url + '", "rowNumber":"'+rowNumber+'"}',
It can cause malformed JSON string.
Instead of this stringify your JavaScript object using JSON.stringify method:
data: JSON.stringify({formUrl: url, rowNumber: rowNumber}),
JSON.stringify will make all job for you to represent your object as valid JSON string.