ASP.NET WebAPIで Port Knockingを作ってみた。
Port Knocking?
システム管理すると、遠隔地のサーバーに管理者としてアクセスする必要があるが往々にある。sshやhttpsで暗号化された通路を使用するが、外部に常時さらされている管理ポートは、brute-force攻撃を受け常だ。
特にsshの場合は、ネット上にtcp/22万うろついボットが存在程度のリスクだが、fail2banやsshguardのような一定回数以上失敗した場合、自動的にシステムのファイアウォール(iptables、pf、firewalld...)を利用して、一定時間ブロックする手法が必要である。
もし常時サービスが必要としていない、すなわち、管理目的のサービスに見合った手法が「ポート - ノッキング( Port Knoking)」である。クライアントは、デーモンの事前約束した文字列を渡して、予め約束されたポートを少しの間だけ開いておく式である。こうするとポートが常に開放される必要はない。
Basic 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 ..."}
具現
referencesに "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を操作するため、管理者権限が必要だ。
改善点
-
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: ...
- proper logging feature
- proper persistent to records
- proper scheduling to automated expiration
- not to show IIS error page
Author And Source
この問題について(ASP.NET WebAPIで Port Knockingを作ってみた。), 我々は、より多くの情報をここで見つけました https://qiita.com/crowdy/items/52400169b7a64572ef26著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .