Asp.net Webservice - Secure call the webservice with jquery AJAX

14,732

Solution 1

There is no such thing as the best way and the answer is always it depends, though it is very unhelpful. You can use forms authentication for example. If you web application using the web service and the web service are part of the same ASP.NET application, the browser can seamlessly send the forms authentication ticket (cookie) for every call to the web service.

In the config file, you can have

<authorization>
        <deny users="?" />
</authorization>

This will deny access to anonymous users and that will cover the web services as well. In other words, unless a user logs in and gets a valid cookie with the ticket, service cannot be used. Of course, you must HTTPS. Otherwise, any one in the middle can get the cookie in the headers and call your service.

Finally, it is not possible to ensure no one call the web service outside of your application in an absolute sense. The above approach ensures none in the middle calls your service. But there is no way to ensure a valid user calls the service directly outside of your application because the web service caller is JavaScript and whatever security you build in JavaScript can be easily figured out by a user by looking at the script or even looking at the traffic from and to the browser. Any end user who is a bit technical, will be able to replay the requests or modify the requests and submit to your web service using valid credentials.

EDIT:-

Here are the more details you are looking for to enable FormsAuthentication.

(1) In Web.config, under <system.web>, make sure you have this.

<authentication mode="Forms">
     <forms loginUrl="Login.aspx" defaultUrl="~/" />
</authentication>
<authorization>
     <deny users="?" />
</authorization>

This will ensure all non-authenticated (anonymous) users are redirected to Login.aspx.

(2) Implement Login.aspx with your login logic to get the user Id and password and validate them against a database or whatever. Once authentication is successful, that is, the user entered ID and password matches what you have in the database, may be in the login button click handler, set the ticket.

protected void Button1_Click(object sender, EventArgs e)
{
    // Do all your login logic here
    // once user ID and password entered by the user are okay, call this

    string ticket = FormsAuthentication.Encrypt(
                        new FormsAuthenticationTicket("userId", false, 15));
    HttpCookie FormsCookie = new HttpCookie(
               FormsAuthentication.FormsCookieName, ticket) { HttpOnly = true };
    HttpContext.Current.Response.Cookies.Add(FormsCookie);
}

(3) Add PrincipalPermissionAttribute to the web method like this.

public class Users : System.Web.Services.WebService
{
    [PrincipalPermissionAttribute(SecurityAction.Demand)]
    [WebMethod]
    public List<User> GetUsers()
    {
        // Same code as what you have now
    }
}

If you now go to any page, you will be redirected to login.aspx where you will need to enter user ID and password and login. On login, the forms authentication cookie will be created and written to the response. From that point onwards, all the requests to your application will bring in the cookie (browser will do that for you). Without logging in, if you go to the web service directly, you will still be redirected to the login page. As I mentioned in my original answer, a logged in user however will still be able to access the web service directly. If JavaScript can do something, a user can do the same.

BTW, web services (asmx) is a deprecated technology.

Solution 2

This is a very important topic for discussion. There can be many ways to do it.

We personally use Service Stack for API's and use a key when we access API. Key is a guid which remains same for Client and Server. If Client and server are same system then there won't be any issues with posting a key.

A very detailed ways to secure is given here http://www.stormpath.com/blog/secure-your-rest-api-right-way http://codebetter.com/johnvpetersen/2012/04/02/making-your-asp-net-web-apis-secure/

Also for further example Building Secure Public API with PHP/MYSQL

Solution 3

One thing you can do to help prevent calls outside the browser is to put a one-time-use token in your page when you build it, then post that during your AJAX call. A simple implementation would be a database table with a bunch of random values (maybe 32-alphanumeric or similar). When you build the page, retrieve one of the values from the table and put it into your page - when you make your AJAX form post, include that value.

On the server side, ensure that value exists in the table, then delete it from the table.

If that service is called again with that value, it will fail because the value is no longer in the table.

This means that in order to generate a valid token, you must first get the page, and then you can only use that token once.

You can put additional checks in there like IP address, user agent, cookie values, expiration dates, etc., and do things like hashing values with a secret key, or other methods of security by obscurity.

In the end though, as Badri indicates, all of this can be spoofed if someone really wants to by simply manually creating the HTTP request that the browser was going to make for the AJAX call. The best you can do is ensure that only valid users can call the service (regardless of the client technology they're using), and that is accomplished through traditional forms authentication.

Share:
14,732

Related videos on Youtube

Jenan
Author by

Jenan

Updated on June 05, 2022

Comments

  • Jenan
    Jenan almost 2 years

    I want to use the webservices with Ajax. What is the best way for the security when calling webservice using ajax? I want to protect against remote call out of the application.

    I have the following webservice for example:

    [WebService(Namespace = "http://tempuri.org/")]
        [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
        [System.ComponentModel.ToolboxItem(false)]
        [System.Web.Script.Services.ScriptService]
        public class Users : System.Web.Services.WebService
        {
    
            [WebMethod]
            public List<User> GetUsers()
            {
                List<User> listUsers = new List<User>();
                User user = new User();
                user.Id = 1;
                user.Name = "John";
    
                User user2 = new User();
                user2.Id = 2;
                user2.Name = "Martin";
    
    
                listUsers.Add(user);
                listUsers.Add(user2);
    
                return listUsers;
            } 
        }
    }
    

    I call the webservice with jquery ajax:

    <script type="text/javascript">
        $(function () {
    
            getUsers();
    
    
            function getUsers() {
    
                $.ajax({
                    type: "POST",
    
                    url: "Webservices/Users.asmx/GetUsers",
    
                    data: "{}",
    
                    contentType: "application/json; charset=utf-8",
    
                    dataType: "json",
    
                    success: function (response) {
    
                        var users = response.d;
    
                        $.each(users, function (index, user) {
    
                            console.log(user.Name);
    
                        });
    
                    },
    
                    failure: function (msg) {
                    }
                });
            }
        });
    </script>
    
  • Jenan
    Jenan almost 11 years
    What type is now used instead of asmx?
  • Jenan
    Jenan almost 11 years
    Thank you very much for your great reminder - "web services (asmx) is a deprecated technology". I use WCF service. Can you edit please your answer for using wcf service? Thank you.
  • Badri
    Badri almost 11 years
    My answer will be the same for WCF as well. For pt. #3, instead of applying [PrincipalPermissionAttribute(SecurityAction.Demand)] on the web method, apply the same in the method of the class that implements the WCF service contract. Instead of WCF, if you plan to use ASP.NET Web API, which is a f/w for building HTTP services, even then the same approach will work. Web API provides an Authorize attribute which you can use in place of PrincipalPermission but basically, it is all about declaratively checking if there is an authenticated identity associated with the current principal.