‏הצגת רשומות עם תוויות soap. הצג את כל הרשומות
‏הצגת רשומות עם תוויות soap. הצג את כל הרשומות

יום שבת, 29 בספטמבר 2012

Web Service Authentication ASP.NET




יש לי חיבה רבה ל Web Services במיוחד של Soap והחלטתי לכתוב מאמר שיסביר כיצד ניתן להגן עליו בסביבה כל כך עויינת שנקראת אינטרנט, אבל לפני שנקפוץ למים העמוקים נעבור בבריכת הילדים על מנת להבין מדוע אנחנו צריכים לשמור על ה Web Services שלנו.

אז כמו שאתם יודעים (בתקווה...) Web Service מכיל בתוכו פונקציות מרוחקות שממקומות בשרת שנותן שירותים לתוכניות שמבצעות קריאות לאותן פונקציות (API) ובעצם מחלקים את תחומי האחריות של התוכנית ובונים מרכז לוגי משותף לכל התוכניות שצריכות שירות מה Service ללא תלות בארכיטקטורה.

נבנה פרויקט חדש ב Visual Studio.



מבנה הפרוייקט


נערוך את קובץ Service1.asmx ונוסיף לתוכו 3 פונקציות:

  public class Service1 : System.Web.Services.WebService
    {
        [WebMethod]
        public string restricted_functionA()
        {
            return "restricted_functionA";
        }

        [WebMethod]
        public string restricted_functionB()
        {
            return "restricted_functionA";
        }

        [WebMethod]
        public string restricted_functionC()
        {
            return "restricted_functionA";
        }
    }


נריץ את ה Web Service בדפדפן ונגיע לדף Webservice1.asmx  שחושף לנו את הפונקציות של ה Web Service , כאן בעצם יש בעייה , אנחנו ממש לא מעוניינים לחשוף את הפונקציות של ה Service שלנו לכל אחד ובמיוחד לא לחשוף אותו בחיפושים ב Google כבר היום ניתן למצוא מליונים Web Services חשופים.


רק כדי להמחיש את הסכנה אני אשתמש ב Google ככלי פריצה וסריקה ( Google Hack) בעזרת החיפוש המתקדם במנוע ניתן לחפש חשיפות לדוגמה, אם נרשום בחיפוש filetype:asmx נקבל את כל הדפים ש Google מצא בסיומת asmx.


מכאן אנחנו מדרדרים וה Web Service שלנו חשוף מתמיד לכל אחד בכל מקום, הגיע הזמן לצאת מהבריכה של הילדים ושאריות ד.נ.א לא רצוי ולעבור לבריכה של הגדולים, קיימות מספר דרכים להגן על ה Web Service משלב ההעלמה מגוגל ותהליך Authentication מול ה Service שלנו.

חשוב לציין שאם ה Web Service שלנו משרת תוכניות שנגישות אליו מכתובות קבועות ניתן למנוע את כל הבלגן בעזרת חוק ב Firewall שיאפשר גישה ל Service רק מכתובות מוכרות, במקרה שה Service ניתן למשתמשים שלא ניתן לדעת את הכתובות שמהן הם יגיעו ל Service נצטרך לנקוט בשיטה אחרת.

קודם כל העלמת השירות מגוגל, נכתוב קובץ robots.txt ונשמור אותו בתיקייה של הפרויקט, נרשום את השורות הבאות:

User-agent: *
Disallow: /

ונמנע מ Google לסרוק את ה Service שלנו, עד כאן היה החלק הפשוט בכל הסיפור ועכשיו נתחיל את תהליך Authentication.

 Forms Authentication

הדרך הפשוטה ביותר לאבטח את ה Web Service שלנו, על מנת לגשת ל Web Service יש להפעיל את פונקצית Login בשביל להתחבר ל Service, מה שקורה בפועל שהשם משתמש והסיסמא נבדקים מול ה DB ובמקרה שהם נכונים ה Web Service רושם Cookie עם Ticket אצל ה Client.

Webservice

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.Services;
using System.Web.Security;

namespace WebService1
{
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    [System.ComponentModel.ToolboxItem(false)]
    public class Service1 : System.Web.Services.WebService
    {
        private string Authenticate(string user, string pass)
        {
            //check the credential from DB or hard coded.
            if (user == "proxytype" && pass == "password")
                return "Proxytype connect";
            else
                return null;
        }

        [WebMethod]
        public bool login(string user, string pass)
        {
            string isLog = Authenticate(user, pass);

            if (isLog != null)
            {
                //return authentication cookie
                FormsAuthentication.SetAuthCookie(user, false);
                return true;
            }
            else
                return false;
        }

        [WebMethod]
        public void logout()
        {
            FormsAuthentication.SignOut();
        }

        [WebMethod]
        public string restricted_functionA()
        {
            //check if user authentication before execute
            if (Context.User.Identity.IsAuthenticated)
               return "Access Granted Restricted FunctionA";
            return "Access Denied Restricted FunctionA";
        }

        [WebMethod]
        public string restricted_functionB()
        {
            //check if user authentication before execute
            if (Context.User.Identity.IsAuthenticated)
                return "Access Granted Restricted FunctionB";
            return "Access Denied Restricted FunctionB";
        }

        [WebMethod]
        public string restricted_functionC()
        {
            //check if user authentication before execute
            if (Context.User.Identity.IsAuthenticated)
                return "Access Granted Restricted FunctionC";
            return "Access Denied Restricted FunctionC";
        }
    }
}


Client

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using example1.localhost;
namespace example1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //create new instance for the webservice
            Service1 myservice = new Service1();
            //create a cookie container for the return 
            //cookie from the web service
            myservice.CookieContainer = new System.Net.CookieContainer();
            
            myservice.login("proxytype", "password");
            Response.Write(myservice.restricted_functionA());

        }
    }
}


למרות שהמשתמש לא יכול להשתמש בפונקציות הן עדיין חשופות והמשתמש עדיין יכול לראות אותם אם הוא יכניס את הכתובת של ה Web Service בדפדפן שלו וזה עדיין לא מספיק מאובטח, המטרה שכל גישה לא מורשה תקבל הודעת שגיאה 401.1 Unauthorized, תחילה יש לשנות הגדרה ב IIS עצמו, בתגית Authentication במצב Feature View יש לבטל את ה Anonymous Authentication , ולהפעיל את ה Basic Authentication:


כשהמשתמש ינסה להכניס את הכתובת של ה Service בדפדפן הוא יצטרך להכניס שם משתמש וסיסמא , במקרה שהם לא נכונים הוא יקבל שגיאה 401.1 Unauthorized.



בשביל להעביר את ה Credentials יש לבצע מספר שינויים ב Client:

using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using example1.localhost;
using System.Net;
namespace example1
{
    public partial class _Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            //create new instance for the webservice
            Service1 myservice = new Service1();
           
            //create net credentials
            CredentialCache myCredentials = new System.Net.CredentialCache();
            NetworkCredential netCred = new NetworkCredential("proxytype", "password");

            //sign the credentials as basic authentication 
            myCredentials.Add(new Uri(myservice.Url), "Basic", netCred);
            myservice.Credentials = myCredentials;

            //create a cookie container for the return 
            //cookie from the web service
            myservice.CookieContainer = new System.Net.CookieContainer();
            
            myservice.login("proxytype", "password");
            Response.Write(myservice.restricted_functionA());
           

        }
    }
}

חשוב מאוד!  

Basic Authentication מתבסס על שמות והסיסמאות של המשתמשים שרשומים במערכת ההפעלה של ה Service, מומלץ ליצור משתמש חדש עם הרשאות מוגבלות , במקרה שאין SSL השם משתמש והסיסמא עוברים כ Clear Text והם חשופים לכל מי שמאזין על הרשת.

סיכום:

משחקי הרשאות עלולות להפוך את העסק למאוד מסורבל וחשוב מאוד לפשט כמה שאפשר את פריסת האבטחה סביב התוכנית שלנו, ניתן להשתמש בצורות Authentication נוספות כמו Windows ו Digest , כמובן לא לשכוח להשתמש ב SSL.

לא לחשוף סתם...

יום שני, 12 בספטמבר 2011

Php Soap Server and .NET Client

Webservices תמיד עניינו אותי ולכן חיפשתי משהו נחמד על מנת שתוכלו להכיר אותם טוב יותר, קיימת תחרות רבה בין 2 השיטות המובילות בתחום, שיטת ה REST הנפוצה במערכות Linux , כמו שראינו במאמרים בעבר , שם מרבית העבודה מתבצעת עם REST , ולכן העבודה היא הרבה יותר קשה לניתוח, כל חברה יכולה לממש את התתמשקות בצורה אישית ללא סטנדרט מסויים ובאחריות המשתמש לנתח את הנתונים בעצמו.
 השיטה השנייה Simple Object Access  Protocol - Soap , מוגדרת כסטנדרט ועל מנת להשתמש בו יש לעמוד בחוקים שלה, מיקרוספט אימצו את השיטה ומבחינתה זאת השיטה הטובה ביותר לפיתוח בפלטפורמות Windows , אני באמת לא יודע מה יותר טוב, עדיין REST פופלרי מאוד אבל Soap מומלץ לעבודה ע"י W3C העולמית שפיתחה עבורו תקן WSDL - Web Services Description Language  , לכן זה נראה לי ויכוח שכנראה אין בו מנצחים ומפסדים וצריכים להכיר את 2 השיטות.

  חשוב מאוד! המאמר הזה מתייחס לעבודה עם Soap בסביבת Linux ונוסה על מערכת הפעלה Fedora. 

 תשתית:

תחילה יש להבין שעבודה עם Soap בסביבת Linux מצריכה Php אבל לא סתם אלא Php 5.0 ומעלה , התמיכה המלאה ב Soap קיימת בגרסה 5 בלבד, גרסאות נמוכות יותר מצריכות עבודה מול כלים של צד שלישי , בקיצור סיפור מהתחת לכן לא מומלץ לשלב Soap במערכות קיימות עם Php נמוך מגרסה 5, וכמובן שרת Apache. יש להתקין את המחלקות של ה Soap ב Php

#: yum install php-soap

* יש להפעיל את ה Apache מחדש,  ולגשת לדף הבדיקות  phpinfo ולראות אם נוספו השורות הבאות:
soap
Soap Client enabled
Soap Server enabled
DirectiveLocal ValueMaster Value
soap.wsdl_cache11
soap.wsdl_cache_dir/tmp/tmp
soap.wsdl_cache_enabled11
soap.wsdl_cache_limit55
soap.wsdl_cache_ttl8640086400

אחרי שהכנו את ה Server נתחיל לרשום את הקוד, כאן העסק מתחלק ל 2 חלקים, חלק הראשון הוא המימוש של הפונקציות והפרמטרים, במקרה הזה נכתוב קובץ עם סיומת Php , בו נכתוב את הקוד עם כמה תוספות, החלק השני הוא החשיפה של ה Webservice בעזרת קובץ WSDL בפורמט Xml.

 נעבור בקצרה על מבנה הקובץ ה Wsdl , ניתן לקבל מידע רחב בנושא בלינק הבא:


  • לפי ה Element אפשר לראות שהפונקציה שחשופה לנו היא HelloWorld , מתחת שם הפונקציה ניתן לראות שיש לה "ילדים" שהם הפרמטרים שהיא מקבלת ומחזירה ומה הסוג שלהם.
  • תגיות PortType פעולות מופשטות להודעות נכנסות ויוצאות.
  • תגיות ה Message מייצגות מידע שמועבר, מאוד חשובים לשלבים הלוגיים של ה Webservice
  • תגיות ה Binding בעצם מייצגות את הפרוטוקול את מבנה ה Data שהוגדר ע"י PortType ספציפי.
  • תגית ה Port מייצגת איזה Port קצה.
  • תגית ה Service מייצגת סדרה של Ports שקשורים ל Service.


מבנה קובץ ה Php הוא מאוד פשוט, יש הצהרה תחילה על אובייקט Server$ שמסוג SoapServer , בשלב ההצהרה נעמיס את שם הקובץ ה WSDL לכן ממולץ שהקבצים ישבו באותה תקייה, לאחר מכן נוסיף לאובייקט את הפונקציה אותה אנו מעוניינים לחשוף ולאחר מכן נחבר את ה Handle על מנת שהיא תופעל. אין יותר מידי מה לפרט על הפונקציה בגדול אנחנו צריכים להוציא את הפרמטר שנשלח ע"י שימוש במערך וע"פ השם שניתן בקובץ ה Wsdl.

 

טיפ להתחלה:
 מומלץ לבנות את ה WSDL ע"ג ה Visual Studio בעזרת יצירת פרויקט Webservice , יש ליצור פונקציות פקטיביות ולאחר מכן לראות את ה WSDL שנוצר ובכך לחסוך את כתיבת ה WSDL , המנגנון האוטמטי ב VS בהחלט עושה את העבודה.

בהצלחה.