Program Language/C#
-
[C#] 한글 2byte 로 계산 하는 방법2020.06.20
-
[C#] MSBuild 빌드 시 C# 언어 버전 변경2020.03.26
-
[C#] C#에서 unsafe 키워드 사용 방법2020.03.10
[C#] HttpWebRequest, WebClient, HttpClient 사용 방식에 대한 정리
우연치 않은 기회가 되어, 각 프로젝트에서 사용하는 HTTP를 호출하는 상황에 대해서 여러 코드를 보게 되었습니다.
몇개의 프로젝트 및 툴들을 조사하다 보니 정말 다양한 방법으로 HTTP를 요청하고 있었는데요.
기회가 된 김에 정리를 한번 해보려고 합니다. 정리를 하다 보니 더 다양하게 알게 되는거 같아서 좋았습니다.
.NET Framework에서 사용하는 방식에 대해서만 정리를 했습니다.
.NET Framework에서 작업할 때 HTTP 요청을 사용하기 위해서는 세가지 방법이 있습니다.
WebRequest (HttpWebRequest)
WebClient
HttpClient
위 class들을 어떻게 사용하는 것이 좋은가? 세가지 class가 다 필요한 것인가? 에대한 질문을 스스로 던져보았는데요.
결론은, 각각 존재해야 하는 이유가 있었습니다. 물론 MSDN를 보게되면 HttpClient를 권장하는 것 같지만
몇가지 이유에 의해서 각각의 Class 들은 존재 해야 합니다.
System.Net.WebRequest
System.Net.WebRequest 는 추상 클래스 입니다. 따라서 이 클래스를 사용하여 HTTP 요청을 사용하려면 HttpWebRequest 또는 FileWebRequest 를 사용해서 작성해야 한다고 합니다.
이 클래스를 이용해서 작업시, Header, Cookie, Protocol 및 시간초과에 액세스 하고 작업할 수 있는 장점이 있으며,
HTTP 요청에 대한 세밀한 컨트롤이 가능한 장점이 있습니다.
가장 많이 접한 class 또한 HttpWebRequest class 였습니다.
System.Net.WebClient
WebClient는 HttpWebRequst의 Wrapper 이므로, 내부적으로는 HttpWebRequest를 사용합니다.
따라서 WebClient는 HttpWebRequest에 비해 약간 느리지만, 적은량의 소스 코드만으로도 동작 할 수 있습니다.
HttpWebRequest가 제공하는 추가 기능을 활용할 필요가 없다면 WebClient를 사용하는 것이 나은 선택입니다.
하지만 이 외에 WebClient는 HttpClient에서 지원하지 못하는, 다운로드를 위한 진행 상황을 제공합니다.
또한, WebRequest와 마찬가지로 FTP를 지원합니다.
이 두 부분이 HttpClient 와 WebClient의 사용성을 구분짓는 것 같습니다.
System.Net.Http.HttpClient
HttpClient 는 .NET Framework 4.5에서 도입되었습니다.
HttpClient는 HttpWebRequest의 유연성과 WebClient의 단순성을 결합하여 제공하기 때문에, 해당 프레임워크를 사용하는 환경이라면, HttpClient 를 사용하는 것을 권장하고 있습니다.
HttpWebRequest는 요청/응답 객체에 대한 많은 제어 기능을 제공하기 때문에, 이러한 기능이 필요하다면 HttpClient 보다는 HttpWebRequest를 사용해야 합니다만, HttpClient는 FTP를 지원하지 않습니다.
HttpClient의 모든 I/O 바인딩 메소드는 비동기식이며, 동일한 HttpClient 인스턴스를 사용해서 동시 요청을 수행할 수 있습니다. 즉, 동기 비동기식을 모두 제공합니다.
HttpClient는 한 번 인스턴스화되고 응용프로그램의 수명주기 전체에서 재사용 하도록 설계되었습니다.
만약 반복적으로 HttpClient를 사용한다면, 매번 할당 후 제거하는 방식이 아닌 한번 사용한 객체를 재사용하도록 설계하여야 합니다. new 키워드로 HttpClient를 생성 할 때마다 사용 가능한 소켓이 많은 트래픽으로 소진되기 때문에 SocketException이 발생 할 수 있습니다.
그러므로 HttpClient의 권장 사용 방법은 단일 공유 HttpClient 인스턴스를 작성 하는 것 입니다.
개인적인 정리
1. .NET Framework 4.5 를 이용하는 환경이라면 HttpClient 를 사용하는 것을 권장합니다.
2. 단. HttpClient를 사용한다면, 단일화된 HttpClient 인스턴스를 생성하고 재사용 하는 것이 좋습니다. (static)
3. HttpClient는 WebClient를 완전히 대체하지 못하기 때문에, 필요에 따라 WebClient를 사용해야 합니다.
4. .NET Framework 4.5 버전을 사용 못하는 환경이라면, HttpWebRequest 와 WebClient의 장점을 비교해서 사용하시면 됩니다.
5. 요청 및 응답에 따른 다양한 제어 및 헤더, 쿠키등등 HTTP의 구성요소를 사용해야 한다면 HttpWebRequest 를 이용하는 것이 좋습니다.
추가 사항
MSDN을 들어가 보면, 위와 같이 새로운 개발환경이라면, WebClient, HttpWebRequest 를 추천하지 않으며,
System.Net.Http.HttpClient Class를 사용하라고 안내문구가 나오고 있습니다.
필요에 따라서 HttpWebRequest는 사용해도 괜찮을거 같지만 이렇게 문구가 적혀있다보니 HttpClient로 넘어가는 작업을 해봐야겠습니다.
하지만, HttpClient는 WebClient가 지원하는 일부 기능을 지원하지 않으니...
정말 필요에 따라 선택해서 사용해야겠습니다.
참고
https://aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong/
https://www.infoworld.com/article/3198673/when-to-use-webclient-vs-httpclient-vs-httpwebrequest.html
https://stackoverflow.com/questions/20530152/deciding-between-httpclient-and-webclient/27737601#27737601
'Program Language > C#' 카테고리의 다른 글
[C#] MessagePack 사용 방법 (0) | 2020.07.13 |
---|---|
[C#] Zeroformatter 사용 방법 (0) | 2020.07.08 |
[C#] 한글 2byte 로 계산 하는 방법 (0) | 2020.06.20 |
[C#] ICloneable 인터페이스를 이용한 객체 복사 (1) | 2020.05.19 |
[C#] MSBuild 빌드 시 C# 언어 버전 변경 (0) | 2020.03.26 |
[C#] 한글 2byte 로 계산 하는 방법
한글을 2byte로 계산하기위해서 기본적으로 이해를 하셔야 하는 부분은 바로 Unicode 입니다.
해당 부분에 대한 이해없이 단순히 Encoding을 이용해서 Byte 수를 계산한다면,
한글자당 2~3 으로 byte수가 변하는 것을 경험하시게 될겁니다.
한줄로 요약한다면,
유니코드는 국제표준 문자표이고 UTF-8은 인코딩 방식입니다.
Unicode는 전세계 언어를 모두 표시할 수 있는 표준코드 입니다.
그래서 언어자체의 의미로 byte 수를 계산하려고 한다면 Unicode로 인코딩 해서 계산하여야 합니다.
그렇지 않다면, 아래와 같은 오류를 범하실 수 있습니다.
string str = "헬로우월드다";
byte[] data = Encoding.Default.GetBytes( str )
int count = data.Length;
// count = 18
기본적으로 System.Text.Encoding 클래스의 Default 를 사용하게 되면 UTF8 인코딩을 이용하게 됩니다.
UTF8 인코딩일 경우 한글 1글자당 3Byte 로 잡히기 때문에
위에 예시처럼 6글자의 한글일 경우 18byte 로 잡히게 됩니다.
즉, 일반적인 웹사이트에서 한글 1글자당 2byte로 표기 해달라는 요청에 UTF8 인코딩을 이용하게 되면,
어긋나는 결과가 나오게 됩니다.
이러한 요청에는 Unicode를 이용하여 Encoding 해줘야 합니다.
string str = "헬로우월드다";
byte[] data = Encoding.Unicode.GetBytes( str )
int count = data.Length;
// count = 12
동일한 예제를 Unicode로만 변경했을 경우, 우리가 원하는 한글 6글자에 12Byte 길이의 값을 가질 수 있습니다.
'Program Language > C#' 카테고리의 다른 글
[C#] Zeroformatter 사용 방법 (0) | 2020.07.08 |
---|---|
[C#] HttpWebRequest, WebClient, HttpClient 사용 방식에 대한 정리 (1) | 2020.06.30 |
[C#] ICloneable 인터페이스를 이용한 객체 복사 (1) | 2020.05.19 |
[C#] MSBuild 빌드 시 C# 언어 버전 변경 (0) | 2020.03.26 |
[C#] C#에서 unsafe 키워드 사용 방법 (0) | 2020.03.10 |
[C#] ICloneable 인터페이스를 이용한 객체 복사
List<T> 혹은 Dictionary 자료구조를 이용해서 Referance Class를 Add 할 경우, 간혹 실수 하는 부분이 있습니다.
Add 시점에 값을 변경할 경우, 기존에 Add 한 영역까지 참조 값이 바뀌는 부분인데요.
new 키워드를 이용해서 반복적으로 Add할 경우에는 문제가 없지만,
foreach ( var item in listData )
{
gamePlayData.Add( new Item{ Index = eventCount++, Score = score } );
}
부득이하게, Global로 선언된 변수를 Add 하는 시점에 값을 변경하는 경우가 발생합니다.
foreach ( var item in listData )
{
item.Index = eventCount++;
item.Score = score;
gamePlayData.Add( item );
}
이럴 경우, listData가 여러개를 가지고 있다면, 기존의 Add 한 item까지 같은 값으로 참조값이 변경되어 집니다.
예제는 간단한 class를 이용해서 new 키워드를 이용해서 값을 넣어도 상관없지만,
class의 크기가 많다면, 코드량이 상당이 증가하게 될텐데요.
이 경우 ICloneable 인터페이스를 이용하게 손쉽게 해결이 가능합니다.
IClonealbe
해당 인터페이스를 사용하면, 기존 개체의 복사본을 만드는 사용자 지정 구현을 제공할 수 있습니다.
ICloneable 인터페이스에는 Object.MemberwiseClone에서 제공 하는 것 이상의 복제 지원을 제공 하기 위한 Clone 메서드인 하나의 멤버가 포함 되어 있습니다.
복제, 전체 복사본 및 단순 복사본 및 예제에 대 한 자세한 내용은 Object.MemberwiseClone 메서드를 참조 하세요.
위 내용이 MSDN에 설명되어져 있는 내용입니다.
https://docs.microsoft.com/ko-kr/dotnet/api/system.icloneable?view=netcore-3.1
구현 방법
Clone 를 이용하려는 Class 에 IClonealbe 인터페이스를 참조하고, Clone() 메소드를 구현하면 됩니다.
이때 MemberwiseClone() 메소드를 이용하시면, 현재 Object의 단순 복사본을 만듭니다.
public class Item : ICloneable
{
public int Index { get; set; }
public int Score { get; set; }
public object Clone()
{
return this.MemberwiseClone();
}
}
'Program Language > C#' 카테고리의 다른 글
[C#] HttpWebRequest, WebClient, HttpClient 사용 방식에 대한 정리 (1) | 2020.06.30 |
---|---|
[C#] 한글 2byte 로 계산 하는 방법 (0) | 2020.06.20 |
[C#] MSBuild 빌드 시 C# 언어 버전 변경 (0) | 2020.03.26 |
[C#] C#에서 unsafe 키워드 사용 방법 (0) | 2020.03.10 |
[C#] SQL Injection 예방 코드 (1) | 2020.02.12 |
[C#] MSBuild 빌드 시 C# 언어 버전 변경
.NET Framework 4.8 환경에서 개발을 진행 하던 도중, 기본 리터럴 기능을 사용할 일이 있었습니다.
직접 사용한 것은 아니지만, 다른 분이 작업한 내용을 우연히 가지고 오는 과정에서 빌드 오류가 발생해서 찾아본 내용이였습니다.
Visual Studio 에서는 정상적으로 빌드가 진행이 되지만, MSBuild 를 이용해서 빌드를 진행하는 과정에서 .NET Framework의 버전은 같으나, 언어 버전이 발생해서 빌드 오류가 발생했습니다.
1. 기본 리터럴 구문의 사용은 C# 7.0 에서는 사용 불가!
public DataModel GetData()
{
return default( DataModel );
}
'기본 리터럴' 기능은 C# 7.0에서 사용할 수 없습니다. 언어 버전 7.1 이상을 사용하세요.
2. 빌드 구성에서의 언어 버전 변경
프로젝트 속성에 들어가면, 빌드에 대한 구성을 변경하는 메뉴를 확인 할 수 있습니다.
아래 화면 우측 하단의 "고급" 메뉴를 클릭해줍니다.
고급 빌드 설정에 들어가면, 언어 버전을 변경하는 메뉴가 보여집니다.
VS에서는 최신 주버전 빌드로 되어 있어 빌드에 무리가 없지만, MSBuild 로 빌드를 할 경우에는 특정 언어 버전을 명시해주는게 좋습니다.
아래와 같이 7.3 버전으로 변경하였습니다.
3. 프로젝트 파일 편집
위 방법으로도 가능하지만, 프로젝트 파일을 직접 변경함으로써, 오류를 수정할 수 있습니다.
LangVersion 을 특정 버전으로 명시해 주면 됩니다.
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<LangVersion>7.3</LangVersion>
</PropertyGroup>
https://docs.microsoft.com/ko-kr/dotnet/csharp/language-reference/configure-language-version
'Program Language > C#' 카테고리의 다른 글
[C#] 한글 2byte 로 계산 하는 방법 (0) | 2020.06.20 |
---|---|
[C#] ICloneable 인터페이스를 이용한 객체 복사 (1) | 2020.05.19 |
[C#] C#에서 unsafe 키워드 사용 방법 (0) | 2020.03.10 |
[C#] SQL Injection 예방 코드 (1) | 2020.02.12 |
[C#] const와 readonly의 차이 (0) | 2020.02.06 |
[C#] C#에서 unsafe 키워드 사용 방법
C# 에서는 일반적으로 포인터를 사용하지 않지만, 간혹 C++ 에서 사용하던 Class를 가져오면서 포인터를 사용해야 하는 경우가 발생한다. 포인터를 사용하면 CLR에서 안전성을 책임지지 못하고, 불완전한 코드가 된다고 하며 에러를 발생하는데, 이렇게 예전 코드를 사용해야 할 경우, 빌드 속성을 변경해줌으로써 unsafe 코드를 사용 할 수 있다.
1. 사용 방법
형식 또는 멤버 선언에서 unsafe 한정자를 사용할 수 있으며, 이렇게 선언해줄 경우 안전하지 않은 컨텍스트로 간주됩니다.
unsafe private uint reload()
{
uint s0 = 0, s1 = 0;
int j = 0;
fixed (uint* p0 = &mt_state[0])
{
uint* pS = p0;
uint* p1 = p0;
... 중략 ...
s1 = mt_state[0];
s1 ^= (s1 >> 11);
s1 ^= (s1 << 7) & 0x9D2C5680;
s1 ^= (s1 << 15) & 0xEFC60000;
}
return (s1 ^ (s1 >> 18));
}
2. fixed 키워드
fixed 지시어는 unsafe 컨텍스트에서만 허용 됩니다.
클래스가 인스턴스화 되면 CLR에 의해 언제든지 메모리가 이동 될 수 있는데, fixed 지시어를 이용하면 해당 코드에 들어간 변수 및 객체는 가비지 콜렉팅이 발생할 때 주소 재배치 대상이 아니게 됩니다.
3. 빌드 속성
unsafe 한정자를 사용할 경우에는 안전하지 않은 코드 허용(F) 를 체크해야지만, 빌드 오류가 나지 않습니다.
'Program Language > C#' 카테고리의 다른 글
[C#] ICloneable 인터페이스를 이용한 객체 복사 (1) | 2020.05.19 |
---|---|
[C#] MSBuild 빌드 시 C# 언어 버전 변경 (0) | 2020.03.26 |
[C#] SQL Injection 예방 코드 (1) | 2020.02.12 |
[C#] const와 readonly의 차이 (0) | 2020.02.06 |
[C#] EditorConfig를 이용한 코딩규칙 정형화 (0) | 2020.01.30 |
[C#] SQL Injection 예방 코드
SQL Injection 이란 Web hacking 기법 중 하나입니다.
웹 애플리케이션의 뒷단에 있는 Database에 쿼리를 보내는 과정 사이에 일반적인 값 외에 악의적인 의도를 갖는 구문을 삽입하여 공격자가 원하는 SQL 쿼리문을 실행하는 기법입니다.
주로 사용자가 입력한 데이터를 제대로 필터링, 이스케이핑 하지 못했을 경우에 발생하며, 요즘의 거의 모든 데이터베이스 엔진은 유저 입력이 의도치 않은 동작을 하는 것을 방지하기 위해 Escape 함수와 Prepared Statement를 제공한다.
SQL Injection 공격의 종류
- 인증 우회 (AB : Auth ByPass)
- 데이터 노출 (DD : Data Disclosure)
- 원격 명령 실행 (RCE : Remote Command Excute)
인증 우회
아이디와 패스워드를 입력하는 로그인 페이지를 타겟으로 행해지는 공격
SQL 쿼리문의 true / false 의 논리적 연산 오류를 이용하여, 로그인 인증 쿼리문이 무조건 true 결과값이 나오게 하여 인증을 무력화 시키는 원리
[ 외부 입력값 ]
ID : admin'--
Password : 1234
[ 실행되는 쿼리문 ]
Select * From Users Where ID = 'admin'-- And Password = '1234'
데이터 노출
타겟 시스템의 주요 데이터 절취를 목적으로 하는 방식이다. Error based, Union based, Blind based, Time based 방식이 있다. 시스템의 에러는 개발자에게 버그를 수정하는 면에서 많은 도움을 주지만 역으로 에러를 이용할 수 있다. 악의적인 구문을 삽입하여 에러를 유발시키는 것이다.
해커는 GET 방식으로 동작하는 url에 추가적인 `query string`을 추가하여 에러를 발생시킬 수 있다. 이에 해당하는 오류가 나타난다면 그것을 가지고 데이터베이스의 구조를 유추할 수 있다. 그렇기 때문에 오류 페이지 또는 오류 메시지가 노출되어서는 안된다.
매개 변수화 된 쿼리를 사용하는 것은 3 단계 프로세스입니다.
- 매개 변수를 사용하여 SqlCommand 명령 문자열을 구성하십시오.
- 적절한 값을 할당하여 SqlParameter 개체를 선언하십시오.
- SqlParameter 개체를 SqlCommand 개체의 Parameters 속성에 할당하십시오.
SqlCommand와 SqlParameter를 사용하면 SQL_Injection에서 안전하게 코드를 작성할 수 있다.
SqlParameter 객체를 통해 전달되는 값은 쿼리에 영향을 끼치지 못하는 문자열로만 인식이 된다.
a or 1=1 -- 이런 코드도 "a or 1=1 --" 식의 문자열로 인식된다.
이런 방식을 Parameterized Query라고 함!
SqlConnection sCon = new SqlConnection("Data Source=000.000.000.000,1433;Initial Catalog=TestDB;User ID=admin;Password=password;Min Pool Size=5;Max Pool Size=100;Connect Timeout=5;Packet Size=8192");
sCon.Open();
SqlCommand sqlCom = new SqlCommand();
sqlCom.Connection = sCon;
sqlCom.CommandText = "select * from AccountTable where user_name=@userName and user_id=@userID";
sqlCom.CommandType = CommandType.Text;
sqlCom.Parameters.Add(new SqlParameter("@userName", SqlDbType.VarChar, 50)).Value = userName.Text;
sqlCom.Parameters.Add(new SqlParameter("@userID", SqlDbType.VarChar, 50)).Value = userID.Text;
SqlDataReader reader = sqlCom.ExecuteReader();
sCon.Close();
안전한 방식으로 쿼리를 필터링하려면 매개 변수를 사용해야합니다.
매개 변수를 사용하는 프로세스에는 세 가지 단계가 있습니다.
SqlCommand 명령 문자열에 매개 변수를 정의하고 해당 속성을 사용하여 SqlParameter 개체를 선언하고
SqlParameter 개체를 SqlCommand 개체에 할당합니다.
SqlCommand가 실행될 때 매개 변수는 SqlParameter 개체에 지정된 값으로 바뀝니다.
'Program Language > C#' 카테고리의 다른 글
[C#] MSBuild 빌드 시 C# 언어 버전 변경 (0) | 2020.03.26 |
---|---|
[C#] C#에서 unsafe 키워드 사용 방법 (0) | 2020.03.10 |
[C#] const와 readonly의 차이 (0) | 2020.02.06 |
[C#] EditorConfig를 이용한 코딩규칙 정형화 (0) | 2020.01.30 |
[C#] SonarQube - 정적분석 (0) | 2020.01.29 |