ASP.NET Web服务 - 使用jQuery AJAX安全调用Web服务

7

我希望使用Ajax调用Web服务。在使用Ajax调用Web服务时,最好的安全方式是什么?我想防止应用程序外部的远程调用。

例如,我有以下Web服务

[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;
        } 
    }
}

我使用jQuery Ajax调用Web服务:

<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>

调用 Web 服务的应用程序是什么?ASP.NET Web Forms、MVC?.asmx 部分是否属于同一应用程序?调用 .asmx 的 Web 应用程序如何进行安全保护?你是否使用了表单身份验证来实现这一点? - Badri
@Badri - 感谢您的提问。我使用ASP.NET Web Forms。asmx文件在同一个应用程序中。我正在开发一个聊天应用程序,希望使用Web服务来保存消息和检索新消息。我想要为聊天发送消息创建安全的Web服务。只有注册用户才能使用聊天功能。为了进行身份验证,我想要使用表单身份验证。 - Jenan
3个回答

10

没有最好的方法,答案总是取决于具体情况而定,虽然这并不是很有用。例如,您可以使用表单身份验证。如果您的 Web 应用程序使用 Web 服务,并且这些 Web 服务是同一ASP.NET应用程序的一部分,浏览器可以无缝地为每个对 Web 服务的调用发送表单身份验证票证(cookie)。

在配置文件中,您可以设置

<authorization>
        <deny users="?" />
</authorization>
这将拒绝匿名用户访问,这也将覆盖Web服务。换句话说,除非用户登录并获取带有票据的有效cookie,否则无法使用服务。当然,您必须使用HTTPS。否则,任何中间人都可以在标题中获取cookie并调用您的服务。
最后,不能以绝对意义确保没有人在应用程序之外调用Web服务。上述方法确保中间没有人调用您的服务。但是,无法确保一个有效用户直接在应用程序之外调用服务,因为Web服务调用者是JavaScript,并且您在JavaScript中构建的任何安全性都可以被用户轻松地通过查看脚本甚至查看从浏览器发送和接收的流量来找出。任何稍微懂技术的终端用户都将能够重放请求或修改请求并使用有效凭据提交到您的Web服务。
编辑:以下是启用FormsAuthentication所需的更多详细信息。
(1)在Web.config中,在<system.web>下,请确保您拥有此选项。
<authentication mode="Forms">
     <forms loginUrl="Login.aspx" defaultUrl="~/" />
</authentication>
<authorization>
     <deny users="?" />
</authorization>

这将确保所有未经身份验证的(匿名的)用户都将被重定向到Login.aspx页面。

(2) 使用您的登录逻辑来实现Login.aspx,以获取用户名和密码,并根据数据库或其他验证它们的方式进行验证。一旦认证成功,也就是说,用户输入的ID和密码与您在数据库中拥有的信息匹配,可以在登录按钮的单击处理程序中设置票证。

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) 将PrincipalPermissionAttribute添加到Web方法中,如下所示。

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

如果您现在前往任何页面,将被重定向到login.aspx,在那里您需要输入用户ID和密码并登录。登录后,会创建表单身份验证cookie并写入响应。从那时起,所有对您的应用程序的请求都将带有该cookie(浏览器将为您执行此操作)。如果未登录,则直接访问Web服务仍将重定向到登录页面。正如我在原始回答中提到的那样,已登录的用户仍然可以直接访问Web服务。如果JavaScript可以做某些事情,用户也可以做相同的事情。

顺便说一下, Web服务(asmx)是一种已弃用的技术。


现在使用什么类型来替代asmx? - Jenan
非常感谢您的友情提醒 - "Web服务(ASMX)是一项已弃用的技术"。我使用WCF服务。您能否修改您的回答,以便使用WCF服务?谢谢。 - Jenan
我的答案对于WCF也是一样的。对于第3点,不要在Web方法上应用[PrincipalPermissionAttribute(SecurityAction.Demand)],而是在实现WCF服务契约的类的方法中应用相同的内容。如果您计划使用ASP.NET Web API(用于构建HTTP服务的框架),那么同样的方法也适用。Web API提供了一个Authorize属性,您可以将其用于替换PrincipalPermission,但基本上,它都是关于声明性地检查当前主体是否有已验证的身份。 - Badri

2
这是一个非常重要的讨论话题。 有很多方法可以做到这一点。
我们个人使用Service Stack来处理API,并在访问API时使用密钥。 密钥是一个GUID,对于客户端和服务器保持不变。 如果客户端和服务器是同一系统,则发布密钥不会有任何问题。
在这里提供了一种非常详细的安全方法: 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/ 此外,以下是更多示例: 使用PHP/MYSQL构建安全的公共API

1
一件可以帮助防止浏览器外调用的事情是在构建页面时在页面中放置一个一次性的令牌,然后在AJAX调用期间发布该令牌。 一个简单的实现方式是使用包含大量随机值(可能为32个字母数字或类似内容)的数据库表格。 在构建页面时,从表格中检索一个值并将其放入页面中-当您进行AJAX表单发布时,请包括该值。
在服务器端,确保该值存在于表格中,然后从表格中删除它。
如果再次使用该值调用该服务,则会失败,因为该值不再存在于表格中。
这意味着为了生成有效的令牌,您必须先获取页面,然后只能使用该令牌一次。
您可以添加其他检查,例如IP地址,用户代理,cookie值,到期日期等,并执行哈希值与秘密密钥的安全性混淆或其他安全方法。
最终,正如Badri所指出的那样,如果有人真的想要这样做,所有这些都可以被欺骗,只需手动创建浏览器将用于AJAX调用的HTTP请求即可。你能做的最好的事情就是确保只有有效的用户才能调用服务(无论他们使用的是什么客户端技术),而这可以通过传统的表单身份验证来实现。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接