진형아빠이야기

안녕하세요.

진형아빠입니다.


정말 간단하면서도 종종 혼동되는 메서드입니다.

empty와 remove...

한번 정리해보았습니다.

이런 코드가 있다고 할때...

<div class="input-group input-group-sm">

<div class="input-group-control">

<input id="popup_search_value" type="text" class="form-control input-sm">

<label id="popup_placeholder_label" for="form_control_1">제목으로 검색합니다.</label>

</div>

</div> 


1. Empty()의 경우!

$('.input-group-control').rempty();를 실행하면 결과(result)는...다음과 같습니다.


<div class="input-group input-group-sm">

<div class="input-group-control">

</div>

</div>


2. Remove()의 경우!

$('.input-group-control').remove();를 실행하면 결과(result)는...다음과 같습니다.

<div class="input-group input-group-sm">

</div>


remove의 경우는 해당하는 셀렉터 본인까지 삭제해버리게 되는거죠.

empty의 경우는 자식 요소들을 깔끔하게 empty(비워 내는) 것이고요.







신고

Comment +0

안녕하세요.

진형아빠입니다.


오늘부터 틈틈히 GoF의 23개 디자인패턴에 대해서 학습하고 예제코드를 돌려볼까합니다.

사실 이전에 읽어봣지만 다 잊어버려서...리마인드 차원에서 정리할까 합니다.


Iterator패턴입니다. 

반복자 패턴이라고 해서 예제 프로그램은 책과 책장의 클래스를 가지고 반복하여 순서대로 책 이름을 출력하는 프로그램입니다.

뭐...간단하게 for or while로 다이렉트 루프를 돌리면 간단하지 않냐고 이야기 하실수도 있지만 그럴경우 실제 사용하는 main과 iterator프로그램 간의 결합이 높아져서 추후 유지보수가 힘들어 질수 있습니다. 뭔가 이런식으로 이야기하면 좀 어려울수 있으니...정확히 맞지 않을수 있지만 예를 들자면...


이글을 보시는 분이 개발한 일부 프로그램을 다른 사람이 사용했을 때를 생각하시면 됩니다.



이렇게 패턴 프로그램 처럼 구현을 했을대 반복의 로직등이 수정되었을 때 해당 클래스만 변경하고 main이 되는 프로그램을 변경할 필요가 없으니 아주 좋쵸.

결합도가 높다고하면...해당 iterator프로그램과 결합된 프로그램 마다 수정을 해줘야 해서 개발자에게는 헬게이트가 열릴겁니다. 


GoF pattern_iterator.zip


위의 첨부 파일은 java 프로젝트로 만든 소스코드로...그냥 java파일 5개를 가지고 살펴보시면 쉽게 이해가 될겁니다. 



신고

Comment +0

안녕하세요.


진형아빠입니다.


이번 포스트는 웹 개발에서 유의해야할 3대 취약요소에 대해서 이야기를 해볼려고 합니다. 

제가 개인적으로 생각하는 웹개발에서의 3대요소는 크게 injection, XSS, CSRF 입니다. 

물론 이런 취약점 이외에도 많은 다른 위험요소가 있겟지만 OWASP의 10대요소...및 빈도 등을 생각할 때 개인적으로 판단한겁니다.


SpringFramework, 전자정부프레임워크(eGovframework)의 경우는 이 부분에 대한 방어를 하는 기법들이 많이 나왔습니다. 

이 부분에 대해서 한번 알아보도록 하겠습니ㅏ. 


1. injection

인젝션의 경우는 url,sql등이 많지만 여기서는 sql인젝션에 대해서 이야기 해보겠습니다. 

사실 얼마전에 뽐뿌라는 사이트도 sql인젝션으로 뚤렸다는데 이 해킹 방법은 초보적이라서 요즘은 이걸로 뚤리는케이스는 좀...의문이 드는 항목입니다. 

일반적인 자바로 하셧다면 prePareStatement로 쿼리를 실행하도록 하면 되고요.


sql 부분을 ibatis 프레임워크로 만들었다면 변수의 인자를 $가 아닌 #으로 받도록 개발이 되어있으면 됩니다. 


변수 입력값이 user_id = 'admin'

select * form PRODUCT where PRD_ID = #user_id#

=> select * form PRODUCT where PRD_ID = ?

=> 등록이 되고

=> ? 에 'admin' 대입되서 들어가서

=> select * form PRODUCT where PRD_ID = 'admin' 실행이됩니다.

select * form PRODUCT where PRD_ID = '$user_id$'

=> user_id 에 'admin' 값을 가져와서

=> select * form PRODUCT where PRD_ID = 'admin'

=> 등록이 되고

=> select * form PRODUCT where PRD_ID = 'admin' 실행이 됩니다.

참고

http://yeonicon.tistory.com/713



2. XSS

크로스 사이트 스크립트 공격 그냥 줄여서 XSS라고 하는데요. 

웹애플리케이션에서 가장 흔하면서 맨날 문제가 되는 녀석입니다.

방법은 in 또는 out으로 나오는 값에 대하여 필터링을 해야합니다. 

백문이 불여일견이라고 한번 보시죠.

다음은 행자부에서 가이드하고 있는 xss방어를 하기 위한 안전한 코드의 예입니다.

보이시나요?? 매번 입력값에 대해서 이렇게 replaceAll하는 코드를 넣으라고 하고 있습니다. 

이걸 그대로 받아들이시고 실제 개발자들에게 개발자분들...이걸 따라서 개선하세요...하면 욕먹기 딱 좋습니다. 

아마도 개발자 눈에는 이렇게 보일겁니다.



그럼 어떻게 해야할까요??

개인적으로는 추천? 하는 2가지 방법에 대해서 말씀드리겠습니다. 전자정부 프레임워크를 사용한다고 가정했을때 다음과 같은 

1번 선수 HTMLTagFilter의 적용


2번 선수 lucy xss servlet filter 의 적용

이렇게 2가지를 전자정보 프레임워크에 적용하는것을 추천합니다. 


참고자료

http://www.slideshare.net/HyeongKyuLee/spring-camp2015-xss

https://github.com/naver/lucy-xss-filter


3. CSRF

가장 방어하기 힘들고 까다로워서 다들 방어를 아예 안하거나 등한시 하는 CSRF공격입니다 .

사실 xss라던지...필터링이 어느정도 잘되면 과연 이 취약점이 직접적인 문제가 될지는 좀 고민?이 되긴하지만 약점이 되는 여지 자체를 없애는것이 가장 BEST라고 생각하기에 방어를 하는게 좋을듯 합니다 .


한번 이렇게 그림을 통해서 알아보면 좀더 쉽게 이해가 될듯 합니다. 

공격자의 코드에 의해서 사용자 본인이 직접 서비스 요청을 해버리는게 문제입니다. 공격자의 밑장빼기롤 인해서 서비스 요청이 되긴했지만 사용자가 직접 요청을 햇다는 점에서 서버측 에서는 해당 요청을 거부할 방법이 없습니다 .

그럼 이 공격은 어떻게 방어 할수 있을까요??

예를 들어 사용자는 CRUD중에서 단순 조회인 R업무를 하려고 했는데...공격자의 숨겨진 코드에 의해서 U, D, C등의 업무가 진행이 되어서 계좌이체, 자료삭제, 권한변경 등의 작업을 수행하는게 문제입니다. 

따라서 서버측에서는 매번의 요청마다 티켓을 발부해서 티켓에는 사용자:tom, 권한:조회(R) 이런식으로 해서 서버와 사용자가 나누어가지게 되는거죠. 그 다음에 사용자의 요청이 올때 티켓을 대조해서 일치하면 OK! 아니면 무시...하는 방법으로 CSRF를 방어할수 있습니다.

이 방법은 모든 요청에 세션 쿠키와 더불어 랜덤하게 생성되는 토큰을 HTTP 파라메터로 제공하는 것입니다. 요청이 오면, 서버는 반드시 그 토큰에 해당하는 값을 가져와서 요청에 있는 실제 값과 비교하고 값이 맞지 않으면 그 요청은 실패 처리합니다.

상태를 변경하는 HTTP 요청에서만 토큰을 사용하도록하여 이런 기대감을 조금은 완화할 수 있겠다. same origin policy로 인해 나쁜 사이트가 응답을 읽어가진 못할테니 그렇게 해도 비교적 안전하다. (즉, READ는 same origin policy로 막으니까 UPDATE만 sychronized token 패턴으로 막아도 된단 소리) 게다가, 랜덤 토큰을 HTTP GET에 넣는건 토큰이 누출될 가능성도 있다.


이런 티켓의 발부와 대조...서비스 요청의 거절등을 바쁜 프로젝트 일정에 구현을 하려면 힘들겁니다. 

아마도 개발하는 AA(애플리케이션 아키텍트)는 이렇게 될겁니다.


그래서 준비했습니다.!!!!!!!

스프링 시큐리티


자바의 설정에서는 다음과 같이 비슷한 코드가 나올겁니다.

@EnableWebSecurity

@Configuration

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


@Override

protected void configure(HttpSecurity http) throws Exception {

http

.csrf()

.and()

…;

}

}

JSP소스코드는 다음과 같이 나올수 있습니다.

<form action=”${logoutUrl}” method=”post”>

<input type=”submit” value=”Log out” />

<input type=”hidden” name=”${_csrf.parameterName}” value=”${_csrf.token}”/>

</form>


여기에서 name=”${_csrf.parameterName}” value=”${_csrf.token}” 의 _csrf의 파라미터와 토큰값은 스프링 시큐리티 모듈에서 자동으로 삽입하고 대조하게 됩니다. 


참고

https://www.owasp.org/index.php/Cross-Site_Request_Forgery_(CSRF)_Prevention_Cheat_Sheet

http://whiteship.me/?p=13833





신고

Comment +0

안녕하세요.

진형아빠입니다.


제가 Spring Scheduler를 사용하면서 Cron 표현식을 잘 몰라서 한번 검색후 반영해보았습니다.


Cron의 실행주기를 설정하는 방법

1. XML로 설정하기...

<property name="cronExpression">

<!--  -->

    <value>* * * * * * *</value>

</property>


2. @어노테이션으로 설정하기 

저 같은 경우는 xml보다 가능한 Java Config로 해결하려고 하다보니...ㅎㅎㅎ

위와 같이 설정을 하였습니다. 

@Scheduled(cron="0 30 02 ? * *")

@Transactional

public void work() {

...

}


왼쪽부터 초 분 시간 일(Day of Month) 월 요일(Day of Week, 1-7 : SUN-SAT) 년도(생략가능) 의 순이다.


표현식

* : 모든 값

? : 특정 값 없음

- : 범위 지정

, : 여러 값 지정 구분에 사용

/ : 초기값과 증가치 설정에 사용

L : 지정할 수 있는 범위의 마지막 값

W : 월~금요일 또는 가장 가까운 월/금요일

# : 몇 번째 무슨 요일 2#1 => 첫 번째 월요일

예제)

"0 0 12 * * ?"      매일 정오 12시에 실행



"0 15 10 ? * *"     매일 오전 10시 15분에 실행


"0 15 10 * * ?"     매일 오전 10시 15분에 실행


"0 15 10 * * ? *"           매일 오전 10시 15분에 실행


"0 15 10 * * ? 2005"    2005년 동안 매일 오전 10시 15분에 실행


"0 * 14 * * ?"      매일 오후 2시부터 시작하여 오후 2시 59분까지 실행


"0 0/5 14 * * ?"            매일 오후 2시부터 2시 55분까지 5분 간격으로 실행


"0 0/5 14,18 * * ?" 매일 오후 2시부터 2시 55분까지, 오후 6시부터 6시 55분까지 5분 간격으로 실행


"0 0-5 14 * * ?"            매일 오후 2시부터 2시 05분까지 분 단위로 실행


"0 10,44 14 ? 3 WED"    3월의 매주 수요일 오후 2시 10분과 2시 44분에 실행


"0 15 10 ? * MON-FRI"   매주 월요일부터 금요일까지 오전 10시 15분에 실행


"0 15 10 15 * ?"            매달 15일 오전 10시 15분에 실행


"0 15 10 L * ?"     매달 마지막 날 오전 10시 15분에 실행


"0 15 10 ? * 6L"            매월 마지막 금요일 오전 10시 15분에 실행


"0 15 10 ? * 6#3"           매월 세번째 금요일 오전 10시 15분에 실행



!! 주의)


요일(Day of Week) 에 명시적인 특정값이 지정되었을 때, 일(Day of Month)의 표현식이 ?나 특정값이 아닌 모든 값(*)으로 설정되었을 때 아래의 Exception이 발생한다. 


Support for specifying both a day-of-week AND a day-of-month parameter is not implemented


출처:http://fmd1225.tistory.com/60

신고

Comment +0

안녕하세요.

진형아빠입니다.


Summernote 사용시 tooltip이 안나와서 ...아니 차라리 안나오면 괜찮은데 에러가 발생해서...

살펴보니 스크립트의 순서문제였습니다.



이미 전세계에 저와 같은 고민을 가지신분들이 계시네요. ㅎㅎㅎ

https://github.com/summernote/summernote/issues/138


결론은...[ Include jquery-ui first, then bootstrap, then the no conflict code. ]

Bootstrap js 를 호출하기 전에 jquery-ui를 호출하셔야 합니다.

신고

Comment +0

안녕하세요.

진형아빠입니다.


요새 게시판 댓글을 작업을 하는데  sql을 어떻게 해야 한방에 좀 쉽게 개발이 될까를 고민중에 있었습니다. 

아마도 제가 고민을 했던 방법보다 더 좋은 방법이 있을듯 하지만...우선 이정도에서 결과를 내고 추가확인을 하려고 합니다.


방법은 2가지를 생각했습니다. 

1. SQL로 처리

자 우선 왼쪽의 첫번째 테이블이 데이터가 있는 테이블입니다.  결과적으로 저 데이터를 보낸다면 댓글들이 엉망이 되서...다시한번 javascript에서 정렬을 하자니 그것도 그다지 좋은거 같지 않습니다 .

물론 결과는 오른쪽의 데이터입니다. 이쁘게 나왔네요. 바로 result set으로 받아서 그대로 순서대로 화면에 출력해주면 될듯 합니다. 뭐 차일드 성 데이터에 대한 인덴트 주시는것은 개인취향으로...ㅎㅎㅎㅎ

                              


  SELECT id, parent_id, content  

   FROM tableA

  order by coalesce(parent_id, id), id


위와 같이 SQL을 주시면... coalesce 에서 값에 따라서 order by를 해서 오른쪽과 같이 결과가 나올수있습니다.

parent_id가 없으면 id, 있으면...parent_id를 주게 됩니다. 그럼 그 값으로 ordering을 하면 되는거죠. 


1. Java Collection.sort로 처리

2번 방법은 우선 왼편의 데이터를 가져와서 List에 담은 후 Java Collection.sort 로 소팅을 하는겁니다. 쿼리의 ordering과 같이 삼항연산자로 order를 주면됩니다.


Collections.sort(lists, new Comparator<BO>() {

    public int compare(BO u1, BO u2) {

    return new CompareToBuilder()

    .append(u1.getParentId()==0?u1.getId():u1.getParentId() , u2.getParentId()==0?u2.getId():u2.getParentId())

        .toComparison();

    }

});

그럼 결과로 아래와 같이 정렬이 되어서 나오는것을 확인하실수 있습니다. 

BO [id=7, parentId=0, name=no.7]

BO [id=9, parentId=7, name=no.7]

BO [id=12, parentId=7, name=no.7]

BO [id=8, parentId=0, name=no.7]

BO [id=14, parentId=0, name=no.7]

신고

Comment +0

안녕하세요.

진형아빠입니다.


요새 Spring data jpa에 푹 빠져서...이것저것을 개발하고 있는 중입니다. 

그러다가 SpringBoot에서는 잘 되던 @OneToMany 의 조회가 제가 만들고 있는 Spring4기반의 프로젝트에서 에러가 발생한다는것을 알았습니다. 

무려 반나절을 고생했는데요. 아마도 요새 게으름에 SpringBoot에 익숙해져버린 탓인듯 합니다.

ㅎㅎㅎㅎㅎ

child object list를 디버깅하면 지속적으로 "com.sun.jdi.InvocationException occurred invoking method." 라는 메세지가 나와서 계속 에러가 났는데요. 트랜잭션을 묶어주지 않아서 발생했던듯 합니다. 

 

아무튼 결과는 해당 메서드에 @Transactional 어노테이션을 추가해서 해결했습니다.


사실 여기는 방법이 2가지가 있는데요. 

1번 방법은 Fetch.LAZY가 아는 EAGER를 사용하는 방법입니다. 

이렇게 할경우...즉시 로딩으로 차일드 테이블의 결과 값을 가져올수 있는 장점은 있습니다만...별로 좋은 모습은 아닌듯 싶습니다. 

parent entity와  childe entity간의 조인이 바로 걸리면서 원하지 않게 많은 데이터를 가져오게 됩니다.


이 그림이 Fetch.LAZY의 실제 동작하는 쿼리이다. parent를 한건 조회후...child의 리스트를 조회해온다. 즉, 쿼리문은 2번을 날리긴하였지만...데이터적으로는 효율적으로 가져왔다고 판단했습니다. 


이 그림은 Fetch.EAGER로 수행한 결과임. 즉 바로 가져오기 위해서 parent와 child의 left outer join을 수행합니다. 

parent가 1건 이고 child 가 10만 건이라면...의미 없는 조인을 통해서 데이터를 더 조회하는듯 하다. 뭐 나도 아직 JPA가 익숙하지 않아서 경우에 따라서 해당 사항은 판단을 하면 되겠슴니당. 


2번 방법은 @Transactional 어노테이션을 추가입니다. 

Fetch.LAZY를 통해서 해결 하는 방법이 메모리 및 성능 저하등에 있어서 이점이 많이 보입니다. 

ProductModel pm = productRepo.findOne(id);  

pm.getChildren();

위와 같은 코드에서는 1번째의 findOne은 문제가 없습니다. 하지만...차일드 객체를 접근하려는 순간 트랜잭션이 유지 되지 않아서 차일드를 조회하지 못합니다 따라서, @Transactional 을 사용해서 메서드의 트랜잭션을 유지하도록 합니다. 



그러고보면...스프링 부트에서는 트랜잭션 관리가 어떻게 되고 있는지 정확히 알아볼 필요가 있어 보입니다. 사실 생각없이 스프링부틀르 썻더니 그냥 되서 스프링4에서 사용했는데 초기 삽질을 좀 했습니다. 역시 B급 개발자의 허접함이 드러나는 순간이었지용.!!!!


참고한 블로그는 다음과 같습니다. 

아라한사님의 JPA : http://www.slideshare.net/meadunhansa/spring-data-jpa-46105441

자바월드 님: http://javaworld.co.kr/85

책은 김영한님의 JPA를 참고했습니다.

신고

Comment +0

안녕하세요.

진형아빠입니다.


SITEMESH3 에서 javascript를 상단에 놓으면 문제가 없겟지만 하단에 스크립트가 위치할 경우...또는, 각 틀을 담당하는 부분이 아닌 content page에서 각각의 javascript를 실행하고 싶을때는 좀 난감해지더군요.

뭐 근성이 있다면...그냥 맨위...또는 모든 스크립트를 layout이나 decorator 에 기술할 수 도 있겟지만...그건 좋은 모습이 아니기에...그냥 각각의 jsp의 스크립트가 페이지 요청시 딱 원하는 위치에 스크립트를 위치하게 하려고 고민해보았습니다. 


물론 이전 2.x대 버전을 사용하신 분들은

"<sitemesh:getProperty property="page.local_script"></sitemesh:getProperty>"  와 같이 사용하셧겟지만...블로그 대로 하면 안될겁니다. 


이유는 sitemesh3에 와서는 기존의 태그들과 달리...

<sitemesh:write property="body"/>

이런 식으로 sitemesh:write의 프로퍼티를 사용해서 설정하게 끔 변경되었습니다.



백문이 불여일타죠...바로 단계단계 알아봅시다. 

Step1

우선 MySiteMeshFilter 클래스를 만들어 줍니다.

public class MySiteMeshFilter extends ConfigurableSiteMeshFilter {

@Override

protected void applyCustomConfiguration(SiteMeshFilterBuilder builder) {

builder.addTagRuleBundle(new Sm2TagRuleBundle());

}

}


Step2

해당 필터를 프레임워크에 등록해줍니다.

FilterRegistration.Dynamic sitemesh = servletContext.addFilter("sitemesh", new MySiteMeshFilter());

sitemesh.addMappingForUrlPatterns(dispatcherTypes, true, "*.jsp");


Step3

decorator 혹은 layout jsp 하단에 <sitemesh:write property="page.local_script"/>와 같이 스크립트가 들어갈 위치를 잡아줍니다.


Step4.

개별 content가 될 jsp의 javascript에서 다음과 같이 스크립트를 작성합니다.

<content tag="local_script">

<script>

$(function() {

$('.tab-pane').click(function(){

  console.log("do something");

});

});

</script>

</content>


이렇게 하고 작성하시면...에러없이...성공적으로 원하는 대로 하단에 스크립트를 위치할 수 있는것을 확인할 수 있습니다. 


신고

Comment +0

기존의 RDB에서 공통 코드로 select 버튼 또는 dropdown, combo버튼등을 만들었는데요.

JPA를 사용하면서 약간 혼란으로 고민을 하다가 저는 이런 방식으로 해결을 했습니다. 


JPA에서 단지 공통코드라는 것을 RDB처럼 구현하기 위해서 무의미한 OnetoOne 또는 OnetoMany등의 연결은 좋은 방향이 아니라고 생각하고 방법을 찾아보았습니다. 결론은 크게 바뀌는게 아니라면...다음과 같이 해서 공통코드를 만들었습니다. 

물론 동적으로 자주 변경하는 경우는 공통코드를 만드는게 좋을거 같다는 다수분들의 의견이있었는데요. 그 부분은 생각할만한거 같습니다. 

아무래도 소스를 자주 고치는것은 힘들수 있으니까요...ㅎㅎ

new ArrayList< EnumClass >(Arrays.asList(EnumClass.values()))

신고

Comment +0

안녕하세요.

진형아빠입니다.

요새는 웹개발도 모바일을 무조건 적으로 많으 고려하시게 될겁니다. 

모바일 적용을 확인할 때 크롬에서 모바일로 확인하기도 하는데요.

어떤 경우는 실제 디바이스에서 확인 해야하는 경우도 있을겁니다. 


그럴때는 PC의 로컬 was의 결과물을 모바일로 표현하기 위해서 고민이 많이 될수 있는데요. 겨우 이거 때문에 서버에 디플로이까지 하자니...너무 번거롭고 말이죠. 여기 아주 간단한 방법을 소개해드립니다.


chrome://inspect/#devices

으로 크롬에서 접속합니다. 핸드폰USB 드라이버를 설치하고 USB와 핸드폰을 연결하면 다음과 같이 크롬의 디바이스 접속정보가 뜹니다. 

그리고 [Port forwarding...] 을 눌러서 저희가 개발하는 WEB 또는 WAS의 PORT를 포워딩하면 됩니다. 

포워딩 후 모바일에서 크롬을 클릭하면 데스크탑의 화면이 모바일로 보여지게 됩니다. 

*모바일에서 개발자 모드를 세팅해놓으셔야 합니다 .


아래는 데스트탑의 화면입니다. 

USB로 연결이 되었다면...모바일에서도 동일한 화면이 나올겁니다. 


신고

Comment +2

티스토리 툴바