홈으로 돌아가기

C#에서 FTP 인증을 사용한 프록시

C# 범용 프록시 서버가 HTTP, HTTPS 및 FTP를 자동 인증으로 지원합니다. USER/PASS 명령을 가로채 비동기 터널링을 사용합니다. IT 전문가를 위한 전체 코드 및 설정 지침.

자동 인증을 사용한 C# FTP 프록시 생성
Advertisement 728x90

FTP 인증 지원 범용 C# 프록시 서버

이 C# 프록시 서버는 로컬 포트에서 연결을 대기하며 트래픽 유형을 감지해 스마트하게 처리하고 전달합니다. FTP의 경우 USER/PASS 명령어를 가로채 자동으로 자격 증명을 주입해 로그인 정보를 대체합니다. HTTP, HTTPS(CONNECT 방식), FTP를 TcpClientNetworkStream만 사용해 지원하며 외부 라이브러리가 필요 없습니다.

아키텍처와 초기화

서버는 TcpListener를 사용해 지정한 포트의 루프백 인터페이스를 모니터링합니다. FTP 자격 증명은 스레드 안전한 ConcurrentDictionary에 저장됩니다.

public class FullProxyServer
{
    private readonly TcpListener _listener;
    private readonly ConcurrentDictionary<string, string> _ftpCredentials;
    
    public FullProxyServer(int proxyPort, string ftpServer, string ftpUser, string ftpPassword)
    {
        _listener = new TcpListener(IPAddress.Loopback, proxyPort);
        _ftpCredentials = new ConcurrentDictionary<string, string>();
        _ftpCredentials.TryAdd(ftpServer, $"{ftpUser}:{ftpPassword}");
    }
}

Program.Main에서 실행:

Google AdInline article slot
static async Task Main(string[] args)
{
    var proxy = new FullProxyServer(8888, "ftp.example.com", "my_username", "my_password");
    await proxy.StartAsync();
}

요청 유형 감지

클라이언트 데이터를 수신한 후 버퍼를 분석합니다:

string request = Encoding.ASCII.GetString(buffer, 0, bytesRead);

if (request.StartsWith("CONNECT"))
{
    await HandleConnectRequest(clientStream, request, id);
}
else if (request.Contains("FTP") || request.Contains("ftp"))
{
    await HandleFtpRequest(clientStream, buffer, bytesRead, id);
}
else
{
    await TunnelConnection(clientStream, buffer, bytesRead, id);
}

이렇게 프로토콜에 따라 트래픽을 라우팅합니다.

CONNECT를 통한 HTTPS 처리

HTTPS의 경우 직접 터널을 설정합니다:

Google AdInline article slot
var parts = connectLine.Split(' ');
string host = targetParts[0];
int port = int.Parse(targetParts[1]);

var targetClient = new TcpClient();
await targetClient.ConnectAsync(host, port);

string response = "HTTP/1.1 200 Connection Established\r\n\r\n";
await clientStream.WriteAsync(responseBytes);

await TunnelBidirectional(clientStream, targetStream, id);

양방향 스트림 복사는 CancellationTokenSource를 사용해 깔끔한 종료를 보장하며 완전 비동기입니다.

private async Task TunnelBidirectional(NetworkStream clientStream, NetworkStream targetStream, string id)
{
    var cts = new CancellationTokenSource();
    
    var clientToTarget = CopyDataAsync(clientStream, targetStream, id, "C->T", cts.Token);
    var targetToClient = CopyDataAsync(targetStream, clientStream, id, "T->C", cts.Token);
    
    await Task.WhenAny(clientToTarget, targetToClient);
    cts.Cancel();
}

자동 인증 FTP 프록시

주요 기능: FTP 명령어를 가로채 수정합니다. 클라이언트가 USER를 보내면 사용자 이름을 교체하고, 서버의 331(비밀번호 필요) 응답 시 PASS를 자동 전송합니다.

private async Task FtpTunnelWithAuth(NetworkStream clientStream, NetworkStream ftpStream,
                                      string username, string password, string id)
{
    bool authenticated = false;
    
    // FTP 서버 응답 가로채기
    if (!authenticated && response.Contains("331")) // 비밀번호 요청
    {
        string passCmd = $"PASS {password}\r\n";
        await ftpStream.WriteAsync(passBytes);
    }
    
    // 클라이언트 명령 가로채기
    if (!authenticated && command.ToUpper().StartsWith("USER"))
    {
        // 우리 사용자 이름으로 교체
        string userCmd = $"USER {username}\r\n";
        await ftpStream.WriteAsync(userBytes);
    }
}

인증 성공(230 응답) 후에는 모든 명령어를 변경 없이 터널링합니다.

Google AdInline article slot

클라이언트 설정

  • 브라우저: HTTP/HTTPS/FTP 프록시를 127.0.0.1:8888로 설정
  • FileZilla 등: 일반 프록시, 호스트 127.0.0.1, 포트 8888

로그로 흐름 확인:

[abc12345] FTP 요청
[abc12345] ->FTP: USER anonymous\r\n
[abc12345] FTP->: 331 사용자 이름 확인, 비밀번호 필요\r\n
[abc12345] 자동 비밀번호 전송
[abc12345] FTP->: 230 사용자 로그인 성공\r\n
[abc12345] 인증 성공

주요 장점

단일 파일에 들어가는 경량 서버로 async/await를 활용해 확장성이 뛰어납니다. 다음에 적합:

  • 기업 네트워크 프록시 제한 우회
  • 클라이언트 설정 변경 없이 FTP 자동화
  • 상세 로깅으로 트래픽 디버깅
  • 명령어 파싱으로 다른 프로토콜 확장

핵심 요약

  • 클라이언트가 인지하지 못하게 FTP USER/PASS 자동 교체
  • NetworkStream으로 비동기 양방향 터널링
  • ConcurrentDictionary로 스레드 안전 자격 증명 저장
  • 완전한 HTTPS CONNECT 및 기본 HTTP 지원
  • .NET 5+ 크로스플랫폼

— Editorial Team

Advertisement 728x90

다음 읽기