我在其余的Web服务世界中是全新的,我在Web上发表了大量文章,试图在ASP.NET中实现REST Web服务(在另一个项目中并行使用webform应用程序)
我想知道WebServices有多安全? 我在这里解释了设置教程:http://www.codeproject.com/Articles/128478/Consuming-WCF-REST-Services-Using-jQuery-AJAX-Call
我可以用jquery调用我的webservices,但是没有安全性。
我是否必须安装在安全的HTTP标头中?如果是这样,怎么样?
我想知道的另一件事:一个看html页面源代码的人会轻易找到“passkey”或“login”/“passowrd”没有?
需要你的帮助:(谢谢
编辑:
我使用此代码通过jquery调用我的Rest服务:
function setHeader(xhr) {
var secretkey = "userid:uCMfSzkjue+HSDygYB5aEg==";
var hashedUrl = secretkey;
var hashedUrlBase64 = hashedUrl.toString();
xhr.setRequestHeader('Authorization', hashedUrlBase64, "1234dgt");
}
$.ajax({
cache: false,
type: "GET",
async: false,
url: rootWS + "ListeService/GetListeSerie" + "(" + listeId + ")",
//data: "{'id':'" + listeId + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
...
},
error: function (msg) {
...
},
beforeSend: setHeader
});
这个代码到我的REST WS:
[WebInvoke(Method = "GET", UriTemplate = "GetListeSerie({id})")]
public List<SeriePourListe> GetListeSerie(string id)
{
if (!Security.AuthenticateUser())
{
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
return null;
}
//do some stuff
}
public static class Security
{
public static bool AuthenticateUser()
{
WebOperationContext ctx = WebOperationContext.Current;
string requestUri = ctx.IncomingRequest.UriTemplateMatch.RequestUri.ToString();
string authHeader = ctx.IncomingRequest.Headers[HttpRequestHeader.Authorization];
// if supplied hash is valid, user is authenticated
if (IsValidUserKey(authHeader, requestUri))
return true;
return false;
}
public static bool IsValidUserKey(string key, string uri)
{
string[] authParts = key.Split(':');
if (authParts.Length == 2)
{
string userid = authParts[0];
string hash = authParts[1];
if (ValidateHash(userid, uri, hash))
return true;
}
return false;
}
private static bool ValidateHash(string userid, string uri, string hash)
{
if (!UserKeys.Contains(userid))
return false;
string userkey = userid;
byte[] secretBytes = ASCIIEncoding.ASCII.GetBytes(userkey);
HMACMD5 hmac = new HMACMD5(secretBytes);
byte[] dataBytes = ASCIIEncoding.ASCII.GetBytes(uri);
byte[] computedHash = hmac.ComputeHash(dataBytes);
string computedHashString = Convert.ToBase64String(computedHash);
return computedHashString.Equals(hash);
}
}
答案 0 :(得分:2)
取决于所需的安全级别。从jQuery调用会打开代码进行检查,并且可能不安全。一种选择是使用从jQuery调用的代理页面,然后代理页面与webservice通信。此时,代理页面可以设置为基于调用ip,host,隐藏表单字段值等来限制访问。
另一个建议是Base64编码所有请求参数。不是超级安全,但需要更多的工作来窥探眼睛进行解码。
如果您的表单是安全的(例如需要登录才能访问),则将当前用户ID传递给Web服务,然后执行查找以确定在执行任何其他处理之前该用户是否存在于Web服务中是最理想的。
Web服务就是它们,对公众开放。如果返回的信息是安全的,则使用凭证进行访问是必须的。但是,如果您没有任何限制(例如登录访问调用页面),那么从jQuery开始,它将始终容易受到攻击。
这些只是选项。希望它有所帮助。
=================附加示例:
代理页(.aspx)
protected void Page_Load(object sender, EventArgs e) {
string result = "";
if (Request.QueryString["srvcmethod"] != null && Request.QueryString["encodedJSONdata"] != null) {
string decodedJSONRequest = encoder.StringFromBase64(Request.QueryString["encodedJSONdata"].ToString().Trim());
string wsdlData = GetWebservice("ccAddressAPI", Request.QueryString["srvcmethod"].ToString().Trim(), decodedJSONRequest);
/*
* Existance of QueryString('callback') indicates a request initiated from JQuery AJAX on remote server
* response must be formatted as JSONP to prevent parse failure (eg 'callback(JSON);' )
*/
if (Request.QueryString["callback"] != null) {
string jsonpCallBack = Request.QueryString["callback"];
result = jsonpCallBack + "(" + wsdlData + ");";
} else {
result = wsdlData;
}
Response.Write(result);
Response.End();
}
}
/// <summary>
/// Performs post to WebService
/// </summary>
/// <param name="srvc">Service File Name</param>
/// <param name="srvcMethod">Method within service to call</param>
/// <param name="jsonData">JSON Serialized form data</param>
/// <returns>JSON Serialized string of webservice response</returns>
private string GetWebservice(string srvc, string srvcMethod, string jsonData) {
string result = null;
string wsdlData = null;
Dictionary<string, object> obj = new Dictionary<string, object>();
//--define webservice url
string currentReq = Request.Url.GetLeftPart(UriPartial.Authority);
string servicepath = "/websrvc/";
string wsdl = currentReq + servicepath + srvc + ".svc/" + srvcMethod;
//--initiate webservice request
try {
byte[] postData = Encoding.UTF8.GetBytes(jsonData);
WebRequest request = WebRequest.Create(wsdl);
request.Method = WebRequestMethods.Http.Post;
request.ContentLength = postData.Length;
request.ContentType = "text/json";
Stream dataStream = request.GetRequestStream();
dataStream.Write(postData, 0, postData.Length);
dataStream.Close();
//--retrieve/store request response
WebResponse response = request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
wsdlData = reader.ReadToEnd();
reader.Close();
response.Close();
} catch (Exception ex) {
logErrors(ex, System.Reflection.MethodBase.GetCurrentMethod().Name);
}
return wsdlData;
}
调用代理页面的jQuery示例
var Base64={_keyStr:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",encode:function(input){var output="";var chr1,chr2,chr3,enc1,enc2,enc3,enc4;var i=0;input=Base64._utf8_encode(input);while(i<input.length){chr1=input.charCodeAt(i++);chr2=input.charCodeAt(i++);chr3=input.charCodeAt(i++);enc1=chr1>>2;enc2=((chr1&3)<<4)|(chr2>>4);enc3=((chr2&15)<<2)|(chr3>>6);enc4=chr3&63;if(isNaN(chr2)){enc3=enc4=64}else if(isNaN(chr3)){enc4=64}output=output+this._keyStr.charAt(enc1)+this._keyStr.charAt(enc2)+this._keyStr.charAt(enc3)+this._keyStr.charAt(enc4)}return output},decode:function(input){var output="";var chr1,chr2,chr3;var enc1,enc2,enc3,enc4;var i=0;input=input.replace(/[^A-Za-z0-9\+\/\=]/g,"");while(i<input.length){enc1=this._keyStr.indexOf(input.charAt(i++));enc2=this._keyStr.indexOf(input.charAt(i++));enc3=this._keyStr.indexOf(input.charAt(i++));enc4=this._keyStr.indexOf(input.charAt(i++));chr1=(enc1<<2)|(enc2>>4);chr2=((enc2&15)<<4)|(enc3>>2);chr3=((enc3&3)<<6)|enc4;output=output+String.fro mCharCode(chr1);if(enc3!=64){output=output+String.fromCharCode(chr2)}if(enc4!=64){output=output+String.fromCharCode(chr3)}}output=Base64._utf8_decode(output);return output},_utf8_encode:function(string){string=string.replace(/\r\n/g,"\n");var utftext="";for(var n=0;n<string.length;n++){var c=string.charCodeAt(n);if(c<128){utftext+=String.fromCharCode(c)}else if((c>127)&&(c<2048)){utftext+=String.fromCharCode((c>>6)|192);utftext+=String.fromCharCode((c&63)|128)}else{utftext+=String.fromCharCode((c>>12)|224);utftext+=String.fromCharCode(((c>>6)&63)|128);utftext+=String.fromCharCode((c&63)|128)}}return utftext},_utf8_decode:function(utftext){var string="";var i=0;var c=c1=c2=0;while(i<utftext.length){c=utftext.charCodeAt(i);if(c<128){string+=String.fromCharCode(c);i++}else if((c>191)&&(c<224)){c2=utftext.charCodeAt(i+1);string+=String.fromCharCode(((c&31)<<6)|(c2&63));i+=2}else{c2=utftext.charCodeAt(i+1);c3=utftext.charCodeAt(i+2);string+=String.fromCharCode(((c&15)<<12)|((c2&63)<<6)|(c3&63));i+=3}}return strin g}}
var data = JSON.stringify({
"EmployeeId": EmployeeId,
"LoginAccountId": LoginAccountId,
"CustomerId": CustomerId,
"CostCentreId": CostCentreId,
"ParentCostCentreId": ParentCostCentreId,
"CostCentreAdministratorId": CostCentreAdministratorId,
"UserType": UserType,
"optionValList": optionValList
});
var jsondata = Base64.encode(data);
var srvcmethod = 'initCostCentreAddressDataProvider';
$.ajax({
url: "[proxypageurl.aspx]",
type: "GET",
cache: false,
contentType: "application/json; charset=utf-8",
dataType: "jsonp",
data: { "srvcmethod": srvcmethod, "encodedJSONdata": jsondata },
error: function (XMLHttpRequest, textStatus, errorThrown) { console.log({ 'XMLHttpRequest': XMLHttpRequest, 'textStatus': textStatus, 'errorThrown': errorThrown }); },
success: function (jsonRes) {
var json = JSON.parse(jsonRes);
//additional processing here
}
});
我讨厌用一个问题回答一个问题,但是你有什么安全需求,以及服务响应的返回类型是什么?
从后面的代码中调用Web方法更加自包含。唯一值得注意的区别是,Web方法通常只能从调用页面或应用程序访问,除非您将响应格式化为JSONP,否则将无法从其他域中获取。 Web服务是公开可用的,默认情况下通常会返回XML,但如果您从Web服务返回JSON,则其他域也无法使用,也不会对您的域提供。
那么可以将您的响应从Web服务格式化为JSON?此时,即使我知道您的服务,我也无法调用它,除非您将其格式化为JSONP。
以上示例将jSONP用于jQuery,因为我的webservice位于调用页面的单独域中。这可以修改为只返回JSON,服务器端逻辑应该仍然有效(但在该用例中它是UNTESTED)。
希望有所帮助。
答案 1 :(得分:1)
所以我编写了自己的代理,它似乎有效:
[System.Web.Services.WebMethod()]
[System.Web.Script.Services.ScriptMethod(ResponseFormat = ResponseFormat.Json)]
public static object Call(string WSUrl)
{
// Create web client.
WebClient client = new WebClient();
client.Encoding = Encoding.UTF8;
// Download string.
JavaScriptSerializer serializer = new JavaScriptSerializer();
return serializer.Deserialize<List<object>>(client.DownloadString(WSUrl));
}
可以使用jquery调用它:
$.ajax({
type: "POST",
url: "http://localhost:14892/common/proxy.aspx/call",
data: "{'WSUrl':'" + rootWS + "ListeService/2/GetListeSerie" + "(" + listeId + ")" + "'}",
contentType: "application/json; charset=utf-8",
dataType: "json",
success: function (response) {
var result = response.d;
var new_record = "";
$.each(result, function (index, res) {
new_record = serieListe(index + 1, res.Id, res.ImageUrl, res.SerieNom, res.SerieSynopsis, res.SerieUrl);
$('#gridElementsListe').append(new_record);
});
},
error: function (msg) {
$('#msg').html("Error while calling web service,,")
}
});
希望它有所帮助。现在我将为我的代理添加一些安全性,因为bphillips建议我。如果您有任何建议有一个良好的安全协议,请不要犹豫,在这里分享;)