Code Programming/C#2018. 6. 28. 10:13

C#을 이용해서 웹페이지로 로그인이 아닌 HttpWebRequest 객체를 이용해서 로그인을 해보았다.

 

인터넷을 검색해보니 유료로 소스를 판매하는 글도 있었고, 로그인 정보를 암호화 하지 않고 전송하는 방법이 많이 있었다.

사실 자바스크립트만 잘 파악하고 C#으로 구현하면 될 문제로 보여 단순한 작업이기도 하고 해서 직접 구현해 보았다.

 

------------------------------------------------------------------------------------------------------------------------------------

우선 네이버 로그인화면의 소스를 보고 구현 순서를 정리했다.

1. 세션정보 가져오기.

2. 암호화할 문자 생성하기.

3. 문자 암호화

4. 로그인 시도

5. 로그아웃 처리

 

참... 없다.

 

순서대로 구현을 해보자.

------------------------------------------------------------------------------------------------------------------------------------

우선 위의 순서에 맞게 메소드를 생성하였다.

 

using System;
using System.Data;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Cryptography;
using System.Text;


        private void LoginNaver()
        {
            CookieContainer cookie = new CookieContainer();
           
            // 1. 세션정보 가져오기
            string strSessionInfo = GetNaverSessionInfo(cookie);

 

            if (String.IsNullOrWhiteSpace(strSessionInfo))
                return;

 

            // 세션정보에는 암호화에 필요한 값들이 콤마(,)로 구분되어 있다.

            string[] arrSessionInfo = strSessionInfo.Split(',');

            string strSessionKey = arrSessionInfo[0];
            string strSessionName = arrSessionInfo[1];
            string strPublicModulusKey = arrSessionInfo[2];
            string strPublicExponentKey = arrSessionInfo[3];
           
            // 2. 암호화할 문자 생성하기
            string strParam = ConvertPassword(strSessionKey, "ID", "Password");

 

            // 3. 문자 암호화
            string strEncParam = EncryptRSA(strPublicModulusKey, strPublicExponentKey, strParam);

 

            // 4. 로그인 시도
            if (TryNaverLogin(cookie, strSessionName, strEncParam))
            {

                // 5. 로그아웃 처리
                TryNaverLogout(cookie);

                MessageBox.Show("Success");
            }
            else
            {
                MessageBox.Show("Fail");
            }
        }

 

------------------------------------------------------------------------------------------------------------------------------------

* 세션정보 가져오기


        private string GetNaverSessionInfo(CookieContainer cookie)
        {
            string strSessionInfo = String.Empty;

 

            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("https://nid.naver.com/login/ext/keys.nhn");
            req.Method = WebRequestMethods.Http.Get;
            req.Accept = "*/*";
            req.Host = "nid.naver.com";
            req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";
            req.Referer = "https://nid.naver.com/nidlogin.login";
            req.CookieContainer = cookie;

 

            using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())
            {
                StreamReader sr = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
                string strResult = sr.ReadToEnd();

 

                try
                {
                    strSessionInfo = strResult;
                }
                finally
                {
                    if (sr != null)
                        sr.Close();
                }
            }

 

            return strSessionInfo;
        }

------------------------------------------------------------------------------------------------------------------------------------

* 암호화할 문자 생성하기


        private string ConvertPassword(string strSessionKey, string strId, string strPassword)
        {
            string strResult = String.Empty;

 

            strResult += Convert.ToChar(strSessionKey.Length).ToString();
            strResult += strSessionKey;
            strResult += Convert.ToChar(strId.Length).ToString();
            strResult += strId;
            strResult += Convert.ToChar(strPassword.Length).ToString();
            strResult += strPassword;

 

            return strResult;
        }

------------------------------------------------------------------------------------------------------------------------------------

* 문자 암호화


        private string EncryptRSA(string strPublicModulusKey, string strPublicExponentKey, string strTarget)
        {
            string strResult = String.Empty;

 

            // 공개키 생성
            RSAParameters publicKey = new RSAParameters()
            {
                Modulus = Enumerable.Range(0, strPublicModulusKey.Length)
                .Where(x => x % 2 == 0)
                .Select(x => Convert.ToByte(strPublicModulusKey.Substring(x, 2), 16))
                .ToArray()
                ,
                Exponent = Enumerable.Range(0, strPublicExponentKey.Length)
                .Where(x => x % 2 == 0)
                .Select(x => Convert.ToByte(strPublicExponentKey.Substring(x, 2), 16))
                .ToArray()
            };

 

            try
            {
                RSACryptoServiceProvider rsa = new RSACryptoServiceProvider();
                rsa.ImportParameters(publicKey);

    

    // 암호화 및 Byte => String 변환

                byte[] enc = rsa.Encrypt(Encoding.UTF8.GetBytes(strTarget), false);
                strResult = BitConverter.ToString(enc).Replace("-", "").ToLower();
            }
            catch (CryptographicException ex)
            {
                strResult = String.Empty;
            }

 

            return strResult;
        }

------------------------------------------------------------------------------------------------------------------------------------

* 로그인 시도

 

로그인 할 때는 단계가 세부적으로 나뉜다.

우선 암호화한 전송값으로 전송한 뒤에는 SSO 인증을 하는 페이지 주소가 응답이 오고,

이 주소로 접속해야 정상적으로 로그인이 처리가 된다.


        private bool TryNaverLogin(CookieContainer cookie, string strEncName, string strEncValue)
        {
            string strNextURL = String.Empty;
           

            // 특정 파라미터가 데이터 객체인듯 한데 여러개의 아이디를 사용해도 딱히 변동사항이 없었다. 그래서 그대로 사용하기로 했다.
            string strParamFormat = @"bvsd=%7B%22uuid%22%3A%22ae68e175-2232-4dae-8058-83ec84fb1cb3%22%2C%22encData%22%3A%22N4IgrmCWAmIFwgIYFMBsAOZBGA7AVgFoAmIgZiIIBZoUD0AGPdO05AY3UoDMAjLNnqRAAaEADdkAJwDOkAPYA7eCHoA6PKqwiQkaQBU5YNgAsAIsjGQ2yeF0QAbaclEBrZAE8AygBdJct9LwANqgMMphopAKAA5g3gCSCt5SYg4AMnIA5oFwIUjw9KJsyi7asHD0AL7CoIjwWKikRSUAtmX11bX1WFjNCC4tAO7tcESd%2BXAAnOh9IAODciOk43VwPU0gxf1Dcoui5ZQr9Xh4s%2FO79CN4lQC6rh4%2Bfm4Z2cFdFaI8yrCzkJf7ynwICOcHQvRAXwQYG0Wx0%2FxA5RAQJBDQ2kIRMPCWgBCBwOGBNQmnE%2Bymhv2xGNx%2BJRPRJCB%2Bm3CRBGIHQ1MJq0mlDp4ExCEgzJxrPZ70mkx5DNhkCEQpwkwJ70oqB5ZMZ%2FJllKR8ppaO%2BfJ0lBZcoVE1QRBV%2Bsghtl2o5x1OEL1vzwLMo6BNqzNFudrvdKPo4PRkuUegAggAhFnau46BSQbyQBwANQcYBsCBhcha0XsyGSKfsadaCzk8PTdkcyHGYQQ0WGkRicUSyUkqXsLxyeVWhTVIBGVTtoPFvZGWBBYtmIzGg56PdhS393JHOMOM69y8p1xnWHNG%2FKqBBJCX85xOBBpHQDpPlPQh5wyr38Em%2FvB1%2FKWAH7ywF8nOJ6IPQB833qacv1QY9lFHZZByIN1f0pLBDhjNwvF8fxkA7N4Jh7IN9U8AAJeIADE9BZD14CPCVLXhRFyLgSgcNJPDCJIsiUVg71ez%2BNiZyIB9cPJHiv3oRj6UtQVNTo3d0VVKUKVo8dRN5X4JIU7clODdUhImD8lwErjrUkw9OKlDU1PeMETPCQzzJ01BAydLiXSFOjLMdKFLWcozt2kxypVQbTVg%2FByPN%2BAKXMPIgHX0qV8Qi3jfNCri4u8r9Jl1MTZgI4jSPitKNMtd08p00hoqY34itSkqZnc5Te2y1jitWIh7yo355Sa%2BoRKs%2FkOqqoL6ESjFyRoyCAJqmTLQ%2FQL6h%2FWrNJ0HoZtBIbZKxeSxsHQC2q4ndlrwYdJvJVTNrAvS%2FKxMzTp0%2BgJvK3arozQ9KEOi7%2BUQ5aPwyuq5JssaYyieNE3sAsiwzIosxzPNkFB9M%2B1EdNfDTW5RDkSRIGQJJEATRQclALhIBkbwAHl0cx7xsfkJQ4FFCd3LFYctgZ6oQHsRBpBJsmsZx6nadeqY6aZsVKhZlo5B5vGQAJomAFlxap%2BBajYaxc0kSnFEViYGbpbW1WZ0REGV5BVfVhREjYQtoCiTIAHE1csbx3E1zk6chXWhefFm2Y5uWeedo2Tb9mmtddp9BbD58DYDqRTfNy3rbtxAHad4OXf592I5F0XDCcYIQDwUgAB96EL9BC9wQuCApPBKGL0vy6LqhtBOOucHLvBK%2Br1A67LrAO%2BIZu25L3v%2B41Jge%2FLohO%2BbyYJ53SuJNQEuS7bnoF%2B0eyJ9nquN6nkvZ4%2FafREaCfu534%2Fa%2BHwu24IDVUA7q%2F%2B4pVBu8fo%2BQFQIf69rgfj7Lq%2BsDFw3rPK%2BP8JI4GXu3QuU9z5IkASXBo5d344D3oXPA3d4HaBwEXABQDRA4EvtfJB8J8B10QZg%2FBr9J6AMAbAvEddYLEKwf%2FIhtCKRyjId3GBFIGBII%2FFQ%2BEYJoGl3gXg1kqDP5l24dodAOCiGNwkpwOus8b48IfvXHBMiqGzwfjIr%2B3dX4yJYbPEBMiQFEKHtoSYkCy6mNEJMURZcz7hRAJMVBboaFiPSnXUgCCvGEN7l49RfdhHwkmFQwJYSv6zz3lYlhZdNH2PMQksRH4bGF0MaIYKE9%2F7aA%2FKg2xqT6ByLLrkrJ9AAn13hB%2BdRGCS6wP4XPGBEkPzRPLj%2FCkH54nlxvhqD8yTy7b0MrOOeqi8lrxXtAn%2Bwz577x6evLJ35W7lzLr%2FEAPRCEH1WTM9Rvc2HjKoavGBMyv57IWesrAxiiG33GQMxunSiDpI6XkogjjC4KJeQUphWSyAT2kT8whiD%2FnrKiss%2FZPyIlIIaS1ZRoSXndIoSCgZ4L1m%2BLnqk0gbzEXflQeQjFJT3kYsqcC786i26XzyaQSF9zKVtN0Vki8p937fgGWfTpDEJ4UqyZQURISPnctQZi15ndvxssoC0ygBKCBtz6ZQSpVBoF5MoLszuJcvKIUhdK95SrTmqsLsMt0E8q4lwNQMugaC8l4HSQQDBlrRHbw7n0vAEiF7l0tXI7eU9Ok1z4fQARlqO5T1eXI6p6CGHQIqQvYZeAv4yv5es8eV9SCJITQMogqzOlL1hcKgg6rN6TMecys02b6l9JPpMxClcy2bMLp6vJ9864d16fWyFbL61tJJRgWF8aGjmMNdiiBdcMGpJwKIxhKLcCoNXsy7BsLaEtIIWCmd6jzENPvOitZuBdX1M6TgbpO68kcJLlQzdvC5n1JaUIq%2BF68noFQauy9BLaHDKUdeqtt6yVQpfZC2hfS2Qbsvfu5l6ABkHqydYsh6iGkOKQXxOu1S3HCJ3IQhDciNVQpaVyP5zLJjqJekQWeKasDhOzTh2NhKEMsJlaksUE8m3aEeZA2eGCKSPNEW3VerHBpkIrRqR5ciDHly4zWupDHGDLNrilR5rbr5iY7fqsTVHhF8foOYtuU8%2BOH3PYq0Qry3kl0018kuElg08Z8Qxytx6yEWZVcZizVCqGsYrgZwFFmgMmeI0ar1DHC1XyrjpkAJA3n%2Ba8iQL5xBS4%2BYJWqnzNaIuhdBVZk1PntHWd0zCt9rH03LIQT58xya0uBbRcZou3ndOYvRSZ8gc6xFkCfQFsglSaEMdKth1jVKJ6lZa7qoufHGVv0MmQNNbrdMctAQ1nlsLa58fFcsrro2CVlcC3KhheL4SwRXd85bkLgWwS%2FiEsDy2gOwNgqB9%2BUVIGMMO1FTxuH%2FW6edcIrNy8QAxh4H4QYThJBEWtlIaI6Mkj4XZsYZQPAIGf3FYNO70BsHQGQHgRARAuCIRwDwdN9lVN9Xe3IT7UgfsKEyH9gH3hQzeF8J2UAKFSRfYAPqIEJ0kbQbYwYgDlgAL0gPYNmAB6DQ9AAAEAAKAA6lEaAOPpD84AHJ6H5x%2BVQ9AADc%2FPhfE2F%2BBZXeh0Zw6SNznACvleqClwAUT0JQBXABhQ3JuzcK%2BN9b03%2FOLdpAAEr86IAr9Q9AUE4Ad7L53bvSCe98SgyYfuneu%2F50HjQIeCPK9bGsLACuACU%2FP7CQDcPzm27AXCLHGFThAbMCdgHpzYUQzO4a54IAAaRdyaAvmw5D2DRjTuH0RvAg%2FL6mdMsF88eG%2BBYKwyAactGQGLSQTsu%2BFnTFXPvKcQDREgAAD2NjTtWOMmfd46ISBvxhECSGgIMffw%2B2CKDYGASQkhMZsEn%2BILfUIFAuAUDjpQc%2FlBX%2BkE3uICsp9gyCA0bqaxegG4N%2FBAJORATnRAHgXMNfZAT%2FQsP2X%2FdMf%2FJeQoQCYA0AkABMUfNnRQYfOQLgLgJwbwTfafeAXNBiTApwaQWQRQGnDmNGUvUgsGMcHffvQvOQNgBweg7wRgwnZg9MVgyndg2MOHFfaAVvL4JA7fYQ%2BfNgWIGnC2dmQIaQhAJfQCevEQhQJOSATIbGFvHMbGLgNGNoVQkAUXBQcgTQ%2BfcXGnZ%2FbwGnXwQ2UoMwsAR%2FZ%2FQYV%2FNg%2BfDGGnHMMATIKIFQu%2FMg3IBQMALnYQcIyI6I%2BwKIiIuI1nQ2PwUfK2RAIib2YwAABUQGiCkFUBlmSKzGQDSIyOBxyLyMkG0BlmkCXxaHsA91MGJhllME4LAFH0Z1EBqLqIaNUAAA0ZY0h8I9A9AsiRBYj4iYiEjJi4iJiJiQBPA2B0Z29rZVBTArAeZ99J95jPBjBjZ7BVAABVeIfCY2So7QXYzglwI%2FCQMo6QYwVQS4tga4pOZAO4zveYvQUwC3C3bwA4r4n4v47QYXGWLItmdwfI4mC3Po8Y6YnY4wK4m45Afnd4uAOAJ4l4iQFEzI93SYBXfnSQegNE3InMKwU2bnJfAge4xE14ggLgTIgAP2kEGC4GEBJPTy4J5m5y4DiAvzgMMPuKZJzFe0wK4IUFSGCIr2UEwB6DwDYCYFID4BoFIBoAcRwDYFQEmENjYADAIWgGgC%2BEwMGGQB4EyHsAEO%2BBEhoFQGVjYGR34DRzBG4B91IC1JwEQC4GmCIBsCNJNLNJpwkAUHFyqLMJlisD8E%2Fy4G8AZObGNkFxd1T3wlMCzzVmiGMCsEl18REmsOUEQANOb2eItLgArCcEwL32kBp3TxKMrMQGL1L0lPvxLKrG8OUHLMrIxgkI%2Fy%2F0QJCLBibLLPZnbOrLkAbNCP7JbIQDbKrIkOx1xxDN7PLAcFLInKwMMBMHoLAGiGiDRhINUKCEKCbOECbJAJXIACsKzjCkhRy%2F8QBQx0YHBtA7zgZ%2Bdww2ZCzRAnyHBpd98PttBwxdgXB%2BdQwkhIAABHEvP8gCloWs%2FnYmewaAfnHwdwXMbQC3BwSAd7SAVCxAFoTCuoUQNC3C%2B8%2FnQojvVC8mC%2FW%2FC3CiifLPcWdM4oAirMKwRC2syXGWTwVC3GJvdmLii%2FDGeci3QwMmSQaXZAesEAG2ffHCxQBkbPNGQI%2FCkAU4%2BwCQBMLg7QeIbMQ2XckANIIwGARAJ3bilC0QfStgQy1ihQSXQ4uMU%2FOHao8Mkcgg7wKyyXTwKQSALgaoxQcWdwPI4ymQSAVIaozwOijvKwUK2CuIZvfwKKrIm2eiyKrosKl3ZALgKQa%2FZEzwNixCzy7ylKtyvK9GAq1nMKjykq7QHItmBMZ%2FfnNIKIPyvIi45ATIOQZErI4nFqtq7KpYyAdvbq9q%2FnY4wa5E44%2Bq3Q4wXSjynq4a%2BIPKloDCpvBkGaoa8azwdwXCpvbQPQRABE6CnayAUfYIvQI6uAsSwYfnF3LMWsnaq%2FHgIwPY1yji7QJMKQGgbQ4E62K2AnYIiwzIH67Id3L6gnQGzMkUkAoAA%3D%3D%22%7D&enctp=1&encpw={0}&encnm={1}&svctype=0&svc=&viewtype=0&locale=ko_KR&postDataKey=&smart_LEVEL=1&logintp=&url=https%3A%2F%2Fwww.naver.com%2F&localechange=&ls=&xid=&pre_id=&resp=&ru=&id=&pw=";


            string strParam = String.Format(strParamFormat, strEncValue, strEncName);

 

            HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create("https://nid.naver.com/nidlogin.login");
            req.Method = WebRequestMethods.Http.Post;
            req.Accept = "text/html, application/xhtml+xml, image/jxr, */*";
            req.Host = "nid.naver.com";
            req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";
            req.Referer = "https://nid.naver.com/nidlogin.login";
            req.CookieContainer = cookie;
            req.ContentType = "application/x-www-form-urlencoded";
            req.ContentLength = strParam.Length;

 

            StreamWriter sw = new StreamWriter(req.GetRequestStream());
            sw.Write(strParam);
            sw.Close();

            
            using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())
            {
                StreamReader sr = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
                string strResult = sr.ReadToEnd();

                try
                {
                    string strStartIndexString = @"location.replace(""";
                    string strEndIndexString = @""");";

 

                    if (strResult.IndexOf(strStartIndexString) < 0)
                        return false;

 

                    // SSO 인증 페이지 주소 가져오기

                    strNextURL = strResult.Substring(strResult.IndexOf(strStartIndexString) + strStartIndexString.Length);
                    strNextURL = strNextURL.Substring(0, strNextURL.IndexOf(strEndIndexString));
                }
                finally
                {
                    if (sr != null)
                        sr.Close();
                }
            }

 

            // SSO 인증 페이지로 접속

            HttpWebRequest reqSSO = (HttpWebRequest)WebRequest.Create(strNextURL);
            reqSSO.Method = WebRequestMethods.Http.Get;
            reqSSO.Accept = "text/html, application/xhtml+xml, image/jxr, */*";
            reqSSO.Host = "nid.naver.com";
            reqSSO.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";
            reqSSO.Referer = "https://nid.naver.com/nidlogin.login";
            reqSSO.CookieContainer = cookie;
           
            using (HttpWebResponse resSSO = (HttpWebResponse)reqSSO.GetResponse())
            {
                StreamReader sr = new StreamReader(resSSO.GetResponseStream(), Encoding.UTF8);
                string strResult = sr.ReadToEnd();

 

                try
                {
                    string strStartIndexString = @"<html><script language=javascript>window.location.replace(""";

 

                    if (strResult.IndexOf(strStartIndexString) < 0)
                        return false;                   
                }
                finally
                {
                    if (sr != null)
                        sr.Close();
                }
            }

 

            // 이부분은 최종적으로 네이버홈으로 다시 접속하는 부분이다.

            HttpWebRequest reqMain = (HttpWebRequest)WebRequest.Create("https://www.naver.com/");
            reqMain.Method = WebRequestMethods.Http.Get;
            reqMain.Accept = "text/html, application/xhtml+xml, image/jxr, */*";
            reqMain.Host = "www.naver.com";
            reqMain.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";
            reqMain.Referer = strNextURL;
            reqMain.CookieContainer = cookie;

 

            using (HttpWebResponse resMain = (HttpWebResponse)reqMain.GetResponse())
            {
                StreamReader sr = new StreamReader(resMain.GetResponseStream(), Encoding.UTF8);
                string strResult = sr.ReadToEnd();

 

                try
                {
                    // 필요한거 작성
                }
                finally
                {
                    if (sr != null)
                        sr.Close();
                }
            }

            return true;
        }

------------------------------------------------------------------------------------------------------------------------------------

* 로그아웃 처리


        private bool TryNaverLogout(CookieContainer cookie)
        {
            HttpWebRequest req = (HttpWebRequest)WebRequest.Create("https://nid.naver.com/nidlogin.logout?returl=https://www.naver.com/");
            req.Method = WebRequestMethods.Http.Get;
            req.Accept = "text/html, application/xhtml+xml, image/jxr, */*";
            req.Host = "nid.naver.com";
            req.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64; Trident/7.0; rv:11.0) like Gecko";
            req.Referer = "https://my.naver.com/new?svgless=true";
            req.CookieContainer = cookie;

 

            using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())
            {
                StreamReader sr = new StreamReader(res.GetResponseStream(), Encoding.UTF8);
                string strResult = sr.ReadToEnd();

 

                try
                {
                }
                finally
                {
                    if (sr != null)
                        sr.Close();
                }
            }

            return true;
        }

------------------------------------------------------------------------------------------------------------------------------------

 

직접 구현을 해보니 Javascript로 구현된 RSA알고리즘을 C#으로 구현하기 위해 공개키값을 적용하는 부분만 잘 살펴보면

누구든지 쉽게 구현이 가능하다고 생각한다.

 

게다가 웹개발자도 아니라서 웹개발자라면 더욱 쉽게 구현이 가능할 것 같다.

'Code Programming > C#' 카테고리의 다른 글

C# - HttpWebRequest 네이버 로그인(보안)  (1) 2018.06.28
C# - Delegate & Event  (0) 2018.06.26
Posted by 개돼지오크

댓글을 달아 주세요

  1. Naver

    일반 웹 브라우저로 로그인했을 때에는 captcha가 안 뜨는데, 이 방법을 쓰면 https://nid.naver.com/nidlogin.login에서 captcha가 떠서 로그인이 안 되네요. 아무래도 bvsd이 값이 실제 브라우저에서처럼 동적으로 생성되지 않아서 그런 것 같은데, bvsd 생성하는 JS 코드가 매우 길고 obfuscate되어 있어서, 분석하기 힘들고 귀찮네요.

    2018.10.27 16:51 [ ADDR : EDIT/ DEL : REPLY ]