Click or drag to resize

보안 토큰을 사용한 안전한 자동 로그인

다른 웹사이트에서 메일캐리어 웹액세스로 이동시 사용자 인증(메일 계정과 암호 입력) 없이 자동으로 로그인 시킬 수 있습니다. 예를 들어 그룹웨어 시스템에 로그인 해서 사용하다가 웹액세스 시스템으로 이동한다면 웹액세스에 다시 로그인해야 하는 번거로움이 있습니다. 이미 그룹웨어에서 인증되었기 때문에 웹액세스 인증 없이 바로 웹액세스의 로그인 상태가 된다면 보다 편리한 환경을 제공할 수 있습니다.

HTTP referer를 검사를 이용한 방법은 구현하기가 매우 간단하지만 보안에 취약한 단점이 있습니다. 보다 안전하게 자동 로그인 기능을 적용하기 위해 임시 보안 토큰을 생성하고 이를 사용해 로그인하는 방법을 제공합니다. 보안 토큰은 유효 기간이 존재하는 임시 토큰으로 유출되어도 사용할 수 없으므로 매우 안전합니다.

Note Note

웹액세스 7.4.3 버전부터는 External/LogonEx._ashx_ 파일 이름을 External/LogonEx.ashx로 변경해야 이 기능을 사용할 수 있습니다.

Note Note

웹모바일 7.4.4.37 버전부터 보안 토큰 기반의 로그인 기능을 지원합니다.

구현 원리
secure sso
  1. 그룹웨어에서 웹메일 페이지를 로딩하기 위해서 AJAX으로 로그온 토큰을 요청합니다.

  2. 그룹웨어의 AJAX 처리 페이지에서는 웹액세스가 제공하는 SingleSignOn 웹서비스의 GetLogonToken 메서드를 호출합니다.

  3. 웹서비스는 로그온을 위한 임시 보안 토큰을 생성해서 반환합니다.

  4. 생성된 보안 토근을 AJAX 응답으로 웹브라우저에 반환합니다.

  5. 웹브라우저는 보안 토큰을 사용해 웹액세스에 접근합니다.

보안 토큰 생성을 위한 암호 설정

웹액세스 루트 폴더에 있는 Web.config 파일에서 아래와 같은 SingleSignOnPassword 키를 찾은 후 복잡한 암호값을 기입합니다.

영문, 숫자, 특수 기호 등을 사용해 구성합니다.

Web.config
<appSettings>
  ......
  <add key="SingleSignOnPassword" value="" />
</appSettings>
Note Note

웹액세스 7.4.4.95 버전과 웹모바일 7.4.4.37 버전부터 SingleSignOnPassword를 사용할 수 있습니다.

그룹웨어에서 웹액세스 자동 로그인 링크 구현

웹액세스로 자동 로그인할 수 있는 링크를 구현합니다.

링크 클릭 시 AJAX을 사용해 웹액세스로 로그인할 수 있는 보안 토큰을 받아옵니다.

AJAX으로 호출하는 페이지 이름은 GetLogonToken.asp 입니다.

아래 구현은 표준 AJAX 구현 예로 jQuery 등을 사용해 구현할 수도 있습니다.

Index.htm
<script type="text/javascript">
    function SingleSignOnWebAccess() {
        // 보안 토큰을 받아올 AJAX 요청을 전송한다.
        // 이곳에서 로그인할 메일 주소를 파라미터로 전송하면 보안상 취약점이 발생하니 유의합니다.
        MakeAjaxRequest("GetLogonToken.asp");
    }

    function MakeAjaxRequest(url) {
        if (window.XMLHttpRequest) { // Mozilla, Safari, ...
            httpRequest = new XMLHttpRequest();
        } else if (window.ActiveXObject) { // IE
            try {
                httpRequest = new ActiveXObject("Msxml2.XMLHTTP");
            } catch (e) {
                try {
                    httpRequest = new ActiveXObject("Microsoft.XMLHTTP");
                } catch (e) {}
            }
        }
        if (!httpRequest) {
            alert('Cannot create an XMLHTTP instance');
            return false;
        }
        httpRequest.onreadystatechange = GotoWebAccess;
        httpRequest.open('GET', url);
        httpRequest.send();
    }

    function GotoWebAccess() {
        if (httpRequest.readyState === 4) {
            if (httpRequest.status === 200) {
                // 반환된 보안 토큰을 사용해 로그온 URL을 구성한다.
                //  - Lang: 기본 언어를 지정하며 ko 또는 en을 지정할 수 있다.
                //  - ReturnUrl: 로그온 성공 후 로딩할 페이지 URL
                var token = httpRequest.responseText;
                var retUrl = "/Default.aspx";
                var url = "http://webaccess_domain/External/LogonEx.ashx?token=" + token + "&Lang=ko&ReturnUrl=" + encodeURIComponent(retUrl);
                console.log("URL: " + url);
                location.href = url;
            } else {
                alert('There was a problem with the request.\n' + httpRequest.responseText);
            }
        }
    }
</script>
<a href="javascript:SingleSignOnWebAccess();">웹액세스 로그인</div>
GetLogonToken.asp 구현

로그온할 메일 주소와 보안 토큰의 유지 시간(초)을 입력으로 사용해 보안 토큰을 반환하는 웹액세스가 제공하는 웹서비스를 호출합니다.

웹서비스를 호출하는 방법에는 SOAP이 있지만 이 예제에서는 HTTP POST를 사용해 구현합니다.

웹서비스 위치는 [웹액세스/WebService] 폴더에 존재하며 singlesignon.asmx 파일입니다.

ASP에서 HTTP POST 호출을 위해 MSXML2.ServerXMLHTTP 오브젝트를 사용하며 입력 파라미터로 로그인할 메일 주소와 보안 토큰 유지 시간(초)을 지정합니다.

웹서비스 실행 결과는 XML로 반환되므로 MSXML2.DOMDocument 오브젝트를 사용해 XML을 해석하고 보안 토큰을 받아 옵니다.

보안 토큰을 사용해 웹액세스에 자동 로그인 할 수 있는 URL을 구성합니다.

보안 토큰 기반으로 생성된 URL은 암호화되어 있어 그 내용을 알 수 없으며 또한 availSec에 의해 지정된 시간이 경과하면 유효하지 않은 토큰이 됩니다.

GetLogonToken.asp
Dim mailAddress, availSec, webAccess, param, httpRequest, postResponse

'이 페이지는 그룹웨어에 로그인 된 상태에서만 사용 가능하도록 구현되어 있어야 합니다.
'그룹웨어의 로그인 처리 메커니즘을 추가하기 바랍니다.

'로그인할 메일 주소
'로그인 상태의 그룹웨어 세션(또는 쿠키)에서 메일 주소를 읽어서 토큰을 생성합니다.
mailAddress = "user@domain"
'암호화된 토큰이 유효한 시간(초)
availSec = 60

'WebAccess가 제공하는 SingleSignOn 웹서비스를 호출해 암호화된 토큰을 받는다.
Set httpRequest = Server.CreateObject("MSXML2.ServerXMLHTTP")
param = "mailAddress=" & mailAddress &  "&availSec=" & availSec
httpRequest.Open "POST", "http://webaccess_domain/webservice/singlesignon.asmx/GetLogonToken", False
httpRequest.SetRequestHeader "Content-Type", "application/x-www-form-urlencoded"
httpRequest.Send param

'반환된 XML 형식의 결과에서 암호화된 토큰을 추출한다.
Dim objXMLDoc, webAccessLogonToken
Set objXMLDoc = Server.CreateObject("MSXML2.DOMDocument.3.0")    
objXMLDoc.async = False    
objXMLDoc.loadXML httpRequest.ResponseText

if (objXMLDoc.parseError.errorCode = 0) Then
    webAccessLogonToken = objXMLDoc.documentElement.text
Else
    webAccessLogonToken = ""
End If    

'로그온 토큰을 반환한다.
Response.CacheControl = "no-cache"
Response.Write webAccessLogonToken
GetLogonToken.ashx 구현

GetLogonToken.asp와 동일한 역할을 담당하는 페이지를 ASP.NET(C#)으로 구현한 것입니다.

GetLogonToken.ashx
<%@ WebHandler Language="C#" Class="GetLogonUrl" %>
using System;
using System.IO;
using System.Net;
using System.Text;
using System.Web;
using System.Xml;

public class GetLogonUrl : IHttpHandler
{  
    public void ProcessRequest(HttpContext context) 
    {
        // 이 페이지는 그룹웨어에 로그인 된 상태에서만 사용 가능하도록 구현되어 있어야 합니다.
        // 
        // 로그인할 메일 주소
        // 로그인 상태의 그룹웨어 세션(또는 쿠키)에서 메일 주소를 읽어서 토큰을 생성합니다.
        string mailAddress = "user@domain";
        // 암호화된 토큰이 유효한 시간(초)
        int availSec = 60;
        // 로그온에 사용될 URL
        string webAccesssLogonToken = "";

        // POST 방식으로 SingleSignOn 웹서비스를 호출해 암호화된 토큰을 받는다.
        string webServiceUrl = "http://webaccess_domain/webservice/singlesignon.asmx/GetLogonToken";
        try
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(webServiceUrl);

            string param = "mailAddress=" + mailAddress + "&availSec=" + availSec.ToString();
            byte[] postdata = Encoding.ASCII.GetBytes(param);
            request.Method = "POST";
            request.ContentType = "application/x-www-form-urlencoded";
            request.ContentLength = postdata.Length;
            using (Stream stream = request.GetRequestStream())
            {
                stream.Write(postdata, 0, postdata.Length);
            }

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            string responseXml = new StreamReader(response.GetResponseStream()).ReadToEnd();

        webAccesssLogonToken= responseXml;

            // XML 형식으로 반환된 결과에서 암호화된 토큰을 추출한다.            
            XmlDocument xml = new XmlDocument();

            xml.LoadXml(responseXml);
            webAccesssLogonToken = xml.DocumentElement.InnerText;
        }
        catch (Exception)
        {
        }

        // 로그온 토큰을 반환한다.
        context.Response.CacheControl = "no-cache";
        context.Response.ContentType = "text/plain";
        context.Response.Write(webAccesssLogonToken);
    }

    public bool IsReusable {
        get {
            return false;
        }
    }
}
웹서비스 사용 제한
Note Note

아래 내용은 IIS 7.0 이상에서 적용 가능합니다.

기본적으로 웹서비스 폴더는 [웹액세스/WebService]이며 웹액세스에 로그인한 상태가 아니면 호출할 수 없는 상태입니다. 이를 타 웹사이트에서 사용할 수 있도록 개방하는 작업이 필요합니다.

웹액세스 루트 폴더에 있는 Web.config 파일에 아래와 같은 <location> 태그를 추가합니다. 웹액세스에 로그인한 상태가 아니더라도 WebService를 사용할 수 있도록 허락하며 동일 서버(127.0.0.1) 내에서만 접근 가능하도록 제한하고 있습니다. 사용하고자 하는 타 웹사이트가 다른 서버에 있다면 해당 서버의 IP를 추가해서 웹서비스를 호출할 수 있도록 해야 합니다.

Web.config
<configuration>
  ......
  <location path="WebService">
    <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
    </system.web>
    <system.webServer>
      <security>
        <ipSecurity allowUnlisted="false">
          <clear/>
          <add ipAddress="127.0.0.1" allowed="true" />
          <add ipAddress="허가할 IP" allowed="true" />
        </ipSecurity>
      </security>
    </system.webServer>
  </location>  
</configuration>

위 기능을 사용하기 위해서는 IIS 추가 기능 중 IP 주소 및 도메인 제한 기능이 설치되어 있어야 하며 Web.config에서 <ipSecurity> 태그를 사용할 수 있도록 아래와 같이 설정되어야 합니다.

  1. IIS(인터넷 정보 서비스) 관리자 실행

  2. 트리에서 최상단 서버 선택

  3. 기능 위임 선택

  4. 기능 목록 중에서 IP 주소 및 도메인 제한을 선택한 후 기능 위임을 읽기/쓰기로 지정

웹 서비스 호출 오류

웹서비스 singlesignon.asmx/GetLogonToken 호출 시 아래와 같은 오류가 발생한다면 Web.config 파일을 추가로 수정해야 합니다. 웹서비스 오류는 윈도우 이벤트 뷰어의 [Windows 로그 > 응용 프로그램]에 기록됩니다.

오류
Exception type: InvalidOperationException 
Exception message: URL이 예기치 않게 '/GetLogonToken'(으)로 끝나 요청 형식을 인식할 수 없습니다.

HTTP POST 방식으로 웹 서비스를 호출할 수 있도록 Web.config 파일에서 <system.web> 영역 아래에 아래와 같이 <webServices> 항목을 추가합니다.

Web.config
<system.web>
  ......
  <webServices>
    <protocols>
      <add name="HttpPost" />
    </protocols>
  </webServices>
  ......
</system.web>