'프로그래밍'에 해당되는 글 92건

01. source file basics :: 2021/05/28 16:59

개발자를 위한

Java Programming Style Guide (ref. Google style guide)

1. Source file basics

  • 파일
    • 소스 파일 명은 대소문자를 구분하여 정확하게 하나만 있는 최상위 클래스와 .java 확장자로 이루어져 있습니다.
  • 파일 인코딩 : UTF-8
    • 소스 파일은 UTF-8 인코딩 되어야 합니다.
  • 특수 문자
    • 공백 문자 (White space characters)
      • 라인 종결자 문자열(sequence) 제외하면, ASCII 가로 공백 문자(0x20) 소스 파일의 어디서나 사용할 있는 유일한 공백 문자입니다.
        1. 문자열(string) 문자 리터럴(character literals) 있는 모든 다른 공백 문자들은 예외(escape)입니다.
        2. (Tab) 문자는 들여쓰기(indentation) 사용하면 됩니다. 
    • 특수 확장열 (Special escape sequences)
      • 특수 확장열(special escape sequences) 가진 모든 문자의 경우, 8진수(ex. \012) 유니코드(\u000a) 특수문자 대신 해당 확장문자 (\b, \t, \n, \f, \r, \”, \’, \\) 사용합니다.
    • Non-ASCII 문자 (non-ASCII characters)
    • 나머지 non-ASCII 문자의 경우, 실제 유니코드 문자(ex.∞) 동등한 유니코드 특수문자(ex. \u221e) 사용됩니다. 유니코드 특수문자가 문자열이나 주석 외부에서 사용되는 것은 정말 권장하지 않지만, 코드를 쉽게 읽고 이해할 있도록 만들기 위한 방법이라면 선택할 있습니다.

Tip : 유니코드 특수문자의 경우, 때때로 실제 유니코드를 사용하는 것이 주석을 설명하는데 매우 유용할 있습니다.

    • Example

Example

Discussion

String unitAbbrev = "μs";

Best : 주석없이 완벽하게 명확함.

String unitAbbrev = "\u03bcs"; // "μs"

Allowed : 하지만 이렇게 작성할 이유가 없음.

String unitAbbrev = "\u03bcs"; // Greek letter mu, "s"

Allowed : 하지만 어색하고 실수하기 쉬움.

String unitAbbrev = "\u03bcs";

Poor : 독자는 이것이 무엇인지 전혀 모름.

return '\ufeff' + content; // byte order mark

Good: 인쇄할 없는 문자에는 특수문자를 사용하고, 필요한 경우 주석 추가.

Tip : 일부 프로그램에서 non-ASCII 문자를 제대로 처리하지 못할 수도 있다는 두려움 때문에 코드의 가독성을 떨어 뜨리면 안 됩니다. 만약 그런 일이 발생한다면, 해당 프로그램은 중단되고, 수정해야만 합니다.

[로그인][오픈아이디란?]
오픈아이디로만 댓글을 남길 수 있습니다
Name
Password
Homepage

Secret

Secure Coding : 입력 데이터 검증 및 표현 (02) Resource Injection :: 2021/02/02 15:31

<02. Resource Injection : 리소스 주입>


발생 원인 : 외부 입력값이 내부 자원에 대한 식별자가 되는 환경에서 입력값에 대한 검증이 없을 경우 발생

영향 : 시스템 내부 자원 접근, 수정, 자원 간의 충돌 발생


Bad Code : Servie No 대한 입력값 검증이 없음

public void createSocket() throws IOException {


   int def = 1000;

   ServerSocket serverSocket;

   Properties props = new Properties();

   String fileName = "file_list";

   FileInputStream in = new FileInputStream(fileName);

   props.load(in);


   //외부 입력 데이터

   String service = props.getProperty("Service No");

   int port = Integer.parseInt(service);


   //외부 입력 데이터로 소켓 생성

   if (port != 0) {

      serverSocket = new ServerSocket(port + 3000);

   }

   else {

      serverSocket = new ServerSocket(def + 3000);

   }

   ......

}


Good Code : 외부 입력값에 대한 기본적인 검증 후, 적절한 값을 할당

public void createSocket() throws IOException {


   int def = 1000;

   ServerSocket serverSocket;

   Properties props = new Properties();

   String fileName = "file_list";

   FileInputStream in = new FileInputStream(fileName);


   //외부 입력 데이터

   String service = "";

   if (in != null && in.available() > 0) {

      props.load(in);

      service = props.getProperty("Service No");

   }


   //외부 입력 데이터 검증

   if ("".equals(service)) {

      service = "1";

   }


   int port = Integer.parseInt(service);

   //외부 입력 데이터에 따른 포트번호 설정

   switch(port) {

      case 1: def + 1; break;

      case 2: def + 2; break;

      case 3: def + 3; break;

      case 4: def + 4; break;

      default: port = def;

   }


   //검증 완료된 포트로 소켓 생성

   serverSocket = new ServerSocket(port);

   ......

}

[로그인][오픈아이디란?]
오픈아이디로만 댓글을 남길 수 있습니다
Name
Password
Homepage

Secret

Secure Coding : 입력 데이터 검증 및 표현 (01) SQL Injection :: 2021/02/02 15:23

<01. SQL Injection : SQL 주입>


발생 원인 : 외부 입력값이 DB Query 작성에 이용되는 환경에서 입력값을 검증하지 않는 경우에 발생

영향 : 조작된 Query 통해 DB 내용이 노출되거나 변조될 있음

Bad Code : Table Name name 대해 검증하지 않은 코드

Connection con = null;

PreparedStatement stmt = null;


try {

   String tableName = pros.getProperty("jdbc.tableName");

   String name = pros.getProperty("jdbc.name");

   String query = "SELECT * FROM " + tableName + " WHERE Name = " + name;

   stmt = con.prepareStatement(query);

   rs = stmt.executeQuery();

   ........


} catch (SQLException slqe) {}

finally {

   rs.close();

   stmt.close();

   con.close();

}


Good Code : Query문의 구조가 변경되지 않는 PreparedStatement 클래스를 이용하여 쿼리를 수행

Connection con = null;

PreparedStatement stmt = null;


try {

   String tableName = pros.getProperty("jdbc.tableName");

   String name = pros.getProperty("jdbc.name");

   String query = "SELECT * FROM ? WHERE Name = ? ";

   stmt = con.prepareStatement(query);

   stmt.setString(1, tableName);

   stmt.setString(2, name);

   rs = stmt.executeQuery();

   ........


} catch (SQLException slqe) {}

finally {

   rs.close();

   stmt.close();

   con.close();

}


<대표적인 취약점>

Case 1 : 서버에서 다음과 같은 쿼리 실행 코드가 있는 경우 취약점 존재

SELECT * FROM " + tableName + " WHERE name = '" + name + "'"


Case 2 (Blind SQL Injection) : 아래 Normal Query Abnormal Query 실행 결과가 같은 경우 취약점 존재

<Server Query> strSQL = "select user_id, name, user_pwd from member where user_id='"&id&'" and user_pwd='"&password&"'

<Normal Query>http://test.com/member/member_login_check.jsp?user_id=hacker&user_pwd=1234

<Abnormal Query>http://test.com/member/member_login_check.jsp?user_id=hacker&user_pwd=1234' and 1=1--

substr(), ascii() 함수 등을 이용하여 서버의 response , 거짓임을 이용하여 데이터 추출하는 방식


Case 3 : Mass SQL Injection

SQL Injetion 탐지 패턴을 우회하기 위해 CAST 함수 이용하여 쿼리문 인코딩하여 공격


Case 4 : Cookie 이용한 공격

 Query String 대한 길이를 제한하거나 서버에서 PreparedStatement 사용하여 해결

[로그인][오픈아이디란?]
오픈아이디로만 댓글을 남길 수 있습니다
Name
Password
Homepage

Secret

KT EPC Cloud 사용기 :: 2021/01/29 20:49

오늘 팀원 중 한명이 KT EPC Cloud에 AWX를 설치하다 실패한 이야기를 했다.


밤을 새워가며 ansible, redis, nginx, memcached, postgresql, rabbitmq, erlang 등을 설치했는데...
결국 실패하여 오늘까지도 설치하지 못했다는 이야기를 듣고 뭔가 이상하다고 생각했다.

사내 보안망에 있는 서버도 아니고, Public Cloud에 있는데 왜 설치가 안 될까?

그래서 개발용 노트북에 VirutalBox를 설치하고, Cent OS 7을 minimal로 설치했다.
그리고 AWX를 설치해 봤는데... 설치가 잘 되더라.

VirtualBox, Cent OS, AWX를 모두 설치하기까지 걸린 시간이 약 2시간 정도.

팀원을 불러서 설치가 잘 된다고 알려줬다.
그런데, 내가 알려준 대로 모든 것을 해봤는데도 안 된다고 했다.

그래서 직접 EPC에 VM을 생성하여 설치를 해 봤는데, yum 설치가 안 된다.

동일한 버전의 Cent OS 서버인데도 VirtualBox에서는 설치가 되고, EPC에서는 설치가 안 된다면...
가장 먼저 들여다 봐야 하는 것은 바로 Cent OS의 Repository.

바로 /etc/yum.repos.d/에 있는 CentOS의 Repository 파일 내용을 살펴보니...
역시, Repository 문제였다.

CentOS-Base.repo 파일을 원복시키고 설치해 보니 AWX 설치가 잘 된다.

2시간 반 만에 모든 문제 해결!!

[로그인][오픈아이디란?]
오픈아이디로만 댓글을 남길 수 있습니다
Name
Password
Homepage

Secret

Nexus Maven Configuration :: 2019/08/03 15:19

1. Nexus Maven Repository를 이용하여 Build

  1. Project의 POM 파일(pom.xml)에 Repository 정보 추가

    <repositories> <repository> <id>sw-central</id> <name>Central Repository</name> <url>{Nexus Server Repository Address}</url> <snapshots> <enabled>false</enabled> </snapshots> <releases> <enabled>true</enabled> </releases> </repository> </repositories>
  2. Project의 POM 파일(pom.xml)에 Plugin Repository 정보 추가

    <pluginRepositories> <pluginRepository> <id>sw-central</id> <name>Central Repository</name> <url>{Nexus Server Repository Address}</url> <snapshots> <enabled>false</enabled> </snapshots> <releases> <enabled>true</enabled> </releases> </pluginRepository> </pluginRepositories>
  3. 설정 완료한 Maven Project Build
    IDE 도구에서 프로젝트를 빌드하거나, VSCode Terminal에서 다음과 같이 실행합니다.

    mvn clean package

    만약 Dependency Library들을 하나의 폴더에 모으고 싶다면 다음과 같이 maven 명령을 실행합니다.

    mvn clean dependency:copy-dependencies package

2. Nexus Maven Repository에 Library 배포

프로젝트 내 다른 개발자의 라이브러리를 참조해야 하거나, 내가 개발한 라이브러리를 다른 개발자들이 참조하여 개발해야 하는 경우가 발생할 수 있습니다.
그런 경우에도, Nexus Repository를 활용하여 라이브러리를 배포할 수 있습니다.
하지만, Nexus Maven Repository에 로컬에서 빌드한 Library를 배포하는 경우에는 다음 사항에 유의해야 합니다.

releasesnapshot을 구분해야 합니다.

  • release : 정식 배포용. 동일한 버전에 대해 재배포 불가
  • snapshot : 개발 및 테스트용. 동일 버전 재배포 가능
    pom.xml 파일 내 [version] 태그의 버전 명에 "SNAPSHOT"이 있으면 snapshot repository로 배포합니다.
  1. Nexus Maven 접근을 위해서 User ID/Password 설정
    Nexus 서버 관리자에게 Nexus 서버에 접근할 수 있는 계정 생성을 신청합니다.
    그 후, 로컬 Maven 저장소로 이동하여 settings.xml 파일을 생성합니다.
    로컬 Maven 저장소는 Terminal에서 다음과 같이 찾을 수 있습니다.

    cd ~/.m2 pwd

    Terminal에서 직접 settings.xml을 생성할 수도 있습니다.

    New-Item -Path C:\Users\USER\.m2\settings.xml -ItemType file -Value "<settings></settings>"

    windows 10 powershell 기준입니다.

    생성된 settings.xml 파일에 생성된 Nexus 서버 계정을 다음과 같이 추가합니다.

    <settings> <servers> <server> <id>sw-central</id> <username>{username}</username> <password>{password}</password> </server> </servers> </settings>

    settings.xml 파일 내 server id는 Project 내 pom.xml 파일의 Repository id와 동일해야 합니다.

  2. 로컬 개발 PC 환경 설정

    로컬 개발 PC에서 외부 https를 호출할 경우, 오류가 발생할 수 있습니다. (개발 망 이슈)

    ex) https://repo.maven.apache.org

    따라서, 이런 경우 Default로 설정되어 있는 Public Maven Central 환경을 disable시켜야 합니다.

    프로젝트의 POM 파일(pom.xml)에 다음 내용을 추가합니다.

    <repositories> <repository> <id>central</id> <name>Central Repository</name> <url>https://repo.maven.apache.org/maven2/</url> <snapshots> <enabled>false</enabled> </snapshots> <releases> <enabled>false</enabled> </releases> </repository> </repositories>
  3. Project의 POM 파일(pom.xml)에 Distribution Management Repository 정보 추가

    <distributionManagement> <repository> <id>sw-central</id> <name>release repository</name> <url>{Nexus Server Release Repository Address}</url> </repository> <snapshotRepository> <id>sw-central</id> <name>snapshot repository</name> <url>{Nexus Server Snapshot Repository Address}</url> </snapshotRepository> </distributionManagement>
  4. Maven Build를 통해서 배포
    다음과 같이 Nexus 서버에 Library를 배포합니다.
    mvn deploy

3. Local Repository(로컬 파일 시스템 내에 있는 라이브러리) 추가

로컬에 있는 라이브러리들이 있는 폴더, 즉 Local Repository는 다음과 같이 POM 파일(pom.xml)에 추가할 수 있습니다.

<repositories> <repository> <id>local-com</id> <url>file://${basedir}/src/main/resources/lib/</url> </repository> </repositories>

[로그인][오픈아이디란?]
오픈아이디로만 댓글을 남길 수 있습니다
Name
Password
Homepage

Secret
< PREV |  1  |  2  |  3  |  4  |  5  |  ...  19  |  NEXT >