Skip to content
isdnetworks
Go back

한 테이블에 여러 주체 자료가 섞여 있었다

관리자 화면에서 상품 목록을 보는데 우리 것이 아닌 상품이 섞여 나왔다. 같은 product 표를 여러 판매자가 쓰고 있었다.

Table of contents

Open Table of contents

구분이 컬럼 하나였다

표에 seller_no 컬럼이 있긴 했다. WHERE 에 그 조건을 넣으면 자기 것만 나온다. 문제는 안 넣은 곳이 있다는 것이었다.

$ grep -rn "FROM product" --include=*.php application/ | wc -l
      47
$ grep -rn "seller_no" --include=*.php application/models/ | wc -l
      19

grep -rn 으로 세니 product 를 쓰는 곳이 47군데인데 seller_no 가 든 곳은 19군데였다. 조건을 붙이는 것이 규칙일 뿐 강제가 아니면 붙이지 않은 자리가 생긴다.

빠진 곳을 찾았다

47군데를 하나씩 보니 세 부류였다. seller_no 조건이 있는 곳이 19개다. 관리자 전용 집계처럼 조건이 필요 없는 곳이 12개다. 조건이 빠진 곳이 16개였다.

목록 화면 몇 개는 눈에 띄었는데 나머지는 조용했다. COUNT(*) 가 전체를 세고 있었는데 화면에는 숫자만 나오니 아무도 안 알아챈다. 목록은 남의 상품 이름이 보여서 드러나지만 집계는 값 하나라 틀려도 티가 안 난다.

조건을 빠뜨리기 어렵게 만들었다

매번 조건을 붙이는 방식은 또 빠뜨린다. base() 하나로 모으고 그 자리에서 where 를 붙였다.

private function base()
{
    return $this->db->where('seller_no', $this->auth->seller_no())
                    ->from('product');
}

public function get_list($limit, $offset) {
    return $this->base()->limit($limit, $offset)->get()->result();
}

base() 를 거치면 새 조회를 만들어도 조건이 자동으로 붙는다. 전체를 봐야 하는 관리자용 조회는 이름이 다른 모델로 뺐다. 이름으로 갈리니 어느 쪽을 쓰는지가 코드에서 보인다.

빠진 곳이 또 생기는 것을 막으려고 검사도 뒀다. base() 를 안 거치고 from('product') 를 직접 부르는 곳을 grep -rn 으로 찾는다. 0 건이 나와야 한다.

이 검사가 실제로 잡는지 확인하려고 일부러 직접 조회 한 줄을 넣고 돌려서 나오는 것을 보고 지웠다. 대조군 없이 0 건만 보면 검사가 아무것도 안 하고 있어도 통과로 읽힌다.

읽기보다 나쁜 쪽

읽기만 문제가 아니었다. UPDATEDELETE 에도 같은 where 가 필요했다.

public function update($productNo, $data)
{
    $this->db->where('product_no', $productNo)
             ->where('seller_no', $this->auth->seller_no())
             ->update('product', $data);
}

이 조건이 없으면 product_no 만 알면 남의 상품을 고칠 수 있다. 다른 판매자의 product_noPOST 를 보내 봤더니 UPDATE 가 그대로 됐다. 읽기는 남의 것을 보는 것이고 쓰기는 남의 것을 바꾸는 것이라 이쪽이 더 나빴다.

자료가 실제로 어떻게 섞여 있는지도 GROUP BY seller_no 로 세어 봤다. 한 판매자 상품이 42개다. 그쪽 관리자 화면에는 product 전체인 5,061개가 보이고 있었다. 숫자를 확인한 뒤에야 문제의 크기를 알았다.

정리


Share this post on:

Previous Post
원인이 하나가 아니었다
Next Post
세션을 DB에 넣었다