ASP.NET WebAPI로 Port Knocking을 만들어 보았다.
Port Knocking?
시스템 관리는 원격지의 서버에 관리자로서 액세스할 필요가 있지만 흔히 있다. ssh나 https로 암호화된 통로를 사용하지만, 외부에 상시 노출되어 있는 관리 포트는 brute-force 공격을 받는다.
특히 ssh의 경우는, 넷상에 tcp/22만 우울한 봇이 존재 정도의 리스크이지만, fail2ban나 sshguard와 같은 일정 회수 이상 실패했을 경우, 자동적으로 시스템의 방화벽(iptables, pf, firewalld... )를 이용하여 일정 시간 차단하는 방법이 필요하다.
항상 서비스가 필요하지 않은, 즉 관리 목적의 서비스에 적합한 방법이 "포트 - 노킹 (Port Knocking)"이다. 클라이언트는, 데몬의 사전 약속한 캐릭터 라인을 건네주어, 미리 약속된 포트를 조금의 사이만 열어 두는 식이다. 이렇게하면 포트가 항상 열릴 필요는 없습니다.
기본 API
제공하는 명령은 다음과 같습니다.
request:
POST -d '{action:"allow", ip:"127.0.0.1", port:8080}' /api/portkock
POST -d '{action:"deny", ip:"127.0.0.1", port:8080}' /api/portkock
response:
when OKay, {"result":"OK"}
when NG, {"result":"NG", "message":"bla bla ..."}
구현
참조에 "C:\Windows\System32\FirewallAPI.dll"을 추가해야 합니다. 다음과 같은 간단한 Controller를 만들어 보았다.
using PortKnockService;
using System;
using System.Runtime.Serialization;
using System.Web.Http;
namespace PortKockWebApi.Controllers
{
public class PortKnockController : ApiController
{
[HttpGet]
public PortKnockResponse DoGet(PortKnockRequest req)
{
return new PortKnockResponse()
{
Result = "NG",
Message = "unknown method"
};
}
[HttpPost]
public PortKnockResponse DoPost(PortKnockRequest req)
{
// need to log here.
if (req.Action.ToLower() == "allow") {
try
{
FirewallUtils.AllowAddressPort(req.Ip, req.Port);
return new PortKnockResponse()
{
Result = "OK",
Message = null
};
}
catch (Exception e)
{
return new PortKnockResponse()
{
Result = "NG",
Message = e.Message
};
}
}
else if (req.Action.ToLower() == "deny")
{
try
{
FirewallUtils.CloseAddressPort(req.Ip, req.Port);
return new PortKnockResponse()
{
Result = "OK",
Message = null
};
}
catch (Exception e)
{
return new PortKnockResponse()
{
Result = "NG",
Message = e.Message
};
}
}
return new PortKnockResponse()
{
Result = "NG",
Message = "unknown error"
};
}
}
[Serializable]
[DataContract(Name = "")]
public class PortKnockRequest
{
[DataMember(Name = "action", IsRequired = true)]
public string Action { get; set; }
[DataMember(Name = "ip", IsRequired = true)]
public string Ip { get; set; }
[DataMember(Name = "port", IsRequired = true)]
public int Port { get; set; }
}
[Serializable]
[DataContract(Name = "")]
public class PortKnockResponse
{
[DataMember(Name = "result")]
public string Result { get; set; }
[DataMember(Name = "message", IsRequired =false)]
public string Message { get; set; }
}
}
구현한 것
동작 확인
실행할 때는 Firewall을 조작하기 때문에 관리자 권한이 필요하다.
curl에서 실행
Powershell에서 결과를 확인했습니다.
개선점
proper listing feature current opened destinations
list opened destinations
request:
GET /api/portkock[?items=50&page=1]
response:
{items:[
{id="", requested_at="", expired_at="", destination={action:"allow", ip:"127.0.0.1", port:8080}, result:{}},
...
]}
proper getting request specific item details feature
request:
GET /api/portkock/<id>
response:
...
Reference
이 문제에 관하여(ASP.NET WebAPI로 Port Knocking을 만들어 보았다.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/crowdy/items/52400169b7a64572ef26텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)